1 READ ME

I recommended you read the ‘README’ files before you work with the EIPAAB database, there are two ‘“’README.md’ and ‘README.csv’, start with the ‘.md’ file (https://github.com/JakeMartinResearch/EIPAAB-database/blob/main/README.md)

2 Welocme

This is the the R markdown script written in R studio (2023.09.0+463 “Desert Sunflower” Release) used to summarise the systematic map database from Martin et al. 2024 “Evidence of the impacts of pharmaceuticals on aquatic animal behaviour (EIPAAB): a systematic map and open access database” (doi: XXXXX).

It is designed to act as a starting point for anyone who wishes to use the ‘Evidence of the Impacts of Pharmaceuticals on Aquatic Animal Behaviour’ (EIPAAB) database for their own projects.

This script was authored by Jake M Martin (jakemartin.org)

Contact: or *P.s Apologies for any spelling mistakes in the script I am dyslexic and this is a very long document

3 R informartion

If you are not familiar with R, here’s a beginners guide (https://www.youtube.com/watch?v=_V8eKsto3Ug).

Here’s a link to download R (https://cran.r-project.org/) and R studio (https://posit.co/products/open-source/rstudio/), and a guide on how to do so.

This is an R markdown file, which makes annotating and running R code more user friendly, it is also easy to reproducible and share in a variate of formates (e.g. PDF). The R code is embed within chunks, and the output for code will be embedded under the chuck.

# This is a chuck

All other text outside of the chucks are annotations (like this). Hashtags used outside of chucks are used to create headers and to structure the file. Hashtags within the chucks are used for more precise annotation within the code.

If you are not familiar with R markdown, here’s a guide (https://www.youtube.com/watch?v=tKUufzpoHDE)

4 Required R packages

These are the R packages required to run the script. I have added them to a list so that I can install them all in one go using the function below called loaded_packages. This function I have made will load all the packages in the list below, if the packages are not already installed, this function will first install them.

If you want to install and load each package separately, you can use the code install.packages() and require(), I have given a example below.

# this installs and load packages need to install pacman
pacman::p_load("tidyverse", "ggraph", "igraph", "ggrepel", "RColorBrewer", "ggtree",
    "treeio", "ape", "gridExtra", "ggdist", "highcharter", "pander", "here")

For ggtree and treeio you may need to run this code for instillation

# if (!requireNamespace('BiocManager', quietly = TRUE))
# install.packages('BiocManager') BiocManager::install('ggtree')

5 Directories

Creating out input and output directories. They will be made within the current parent directory (i.e. where the R sciprt is saved)

This is code creates a folder and saves the directory as figure_path. This is where we will export our figures

figures_path <- here("figures")

if (!dir.exists(figures_path)) {
    dir.create(figures_path)
}

This is code creates a folder and saves the directory as output_path This is where we will export our data

output_path <- here("output-data")

if (!dir.exists(output_path)) {
    dir.create(output_path)
}

Input directory

input_path <- here("input-data")

if (!dir.exists(figures_path)) {
    dir.create(figures_path)
}

6 Database informartion

The ‘Evidence of the Impacts of Pharmaceuticals on Aquatic Animal Behaviour’ (EIPAAB) database has 96 columns and 1754 rows. The columns represent various forms of metadata extracted from articles that were included in Martin et al. 2024 “Evidence of the impacts of pharmaceuticals on aquatic animal behaviour: a systematic map and open access database” (doi: XXXXX).

The READ-ME file which explains what each metadata is, how it was extracted, what structure it has, and at what level it applies, is available at XXX. Below I have imported the read me for accessibility. I highly recommend you read the READ-ME before conducting any of your own meta-analysis to make sure you have interoperated the data correctly.

More generally, column names that start with ‘validity’ are metadata relating to study validity, those that start with ‘specie’s relate to species information (population), those that start with ’compound’ relate to the chemical information (exposure), those that start with ‘behav’ relate to behaviour information (outcome). The order of columns reflects both the level the metadata is extracted at (i.e. article level or species by compound level; see level in READ-ME), as well as the general category of metadata (i.e. validity, species, compound, behaviour).

setwd(input_path)

READ_ME <- read.csv("READ-ME.csv", na = "NA")  # loading the READ-ME file

7 Importing EIPAAB database

Importing the EIPAAB-database.csv database (accessed from: https://osf.io/atwy6/).

If the CSV files are in the same working directory (wd) as this R script, you will not need to use setwd(), but if the files are located elsewhere you will need to specify this in setwd(), and run all lines at once. In R markdown the working directory changes back to default after the chuck is run.

setwd(input_path)

EIPAAB_database <- read.csv("EIPAAB-database.csv", na = "NA")

8 Total numbers

The first thing we will look at is how many unique (distinct) articles there are in the database, and how many rows of data there are.

There are 901 articles, with 1740 rows.

EIPAAB_database %>%  
  dplyr::distinct(article_id) %>% # Returns a list of distinct article_id
  nrow(.) # Returns the length of the current file (which is the list of distinct article_id)
## [1] 901
EIPAAB_database %>% 
  nrow(.) # Returns the length of the current file (which is the length of the whole datafile)
## [1] 1740

Each row represent a unique species by compound combination within a given article. This is represented by the column unique_row_id This is a combination of the extractors response id, specie,s and compound. For example, R_0Bqz2RQ4JxPfBkZ_Danio_rerio_Diazepam, response id = R_0Bqz2RQ4JxPfBkZ, species = Danio rerio, and compound = Diazepam

EIPAAB_database %>% 
  dplyr::select(unique_row_id) %>% # selects just the unique_column_id column
  dplyr::arrange(unique_row_id) %>% # arranges the column alphabetically so the same examples will be given everytime 
  dplyr::slice(1:10) # Returns only the first 10 rows
##                                                       unique_row_id
## 1                            R_0Bqz2RQ4JxPfBkZ_Danio_rerio_Diazepam
## 2                 R_0CHlDBs9ipt4suZ_Astyanax_mexicanus_Aripiprazole
## 3            R_0Ck0AOjLDWukBUt_Procambarus_clarkii_Chlordiazepoxide
## 4                        R_0JvaI9dlvTbozUl_Daphnia_magna_Fluoxetine
## 5                        R_0JvaI9dlvTbozUl_Daphnia_magna_Sertraline
## 6                        R_0Srt7zn9MwHKne1_Danio_rerio_Escitalopram
## 7                      R_0p8ZEROmCGlSR7r_Oryzias_latipes_Fluoxetine
## 8  R_10C0XxjAUoZmibO_Amphiprion_ocellaris_17-alpha-ethinylestradiol
## 9                         R_10GdzsXlrkwamUt_Daphnia_magna_Cisplatin
## 10          R_10NOT0XWL5TXN5m_Coenagrion_hastulatum_Diphenhydramine

Now the number of total treatments represented in the data, this is the total number of unique doses per species by compound combination.

In the map the number of treatments was only extracted for water-borne exposures, the NAs, represent other exposure routes. Therefore, the number of water-borne exposures treatments are 6294, and there are an additional 226 articles that don’t have treatment numbers. We know they all have at least two treatments, a control and a compound of interest, because that is part of the inclusion criteria. So we could add the number of NAs * 2 to the total, this would be 6746 total treatment groups. Although, this would likely be an underestimate of the true total.

EIPAAB_database %>% 
  dplyr::summarise(
    groups = sum(compound_treatment_levels, na.rm = TRUE), # Calculate the sum of 'compound_treatment_levels' while ignoring NA values
    nas = sum(is.na(compound_treatment_levels)), # Count the number of NA values in 'compound_treatment_levels'
    total = groups + (nas * 2) # Calculate the total by adding 'groups' to twice the number of NAs
  )
##   groups nas total
## 1   6154 226  6606

9 Study motivation

Let’s look at how the evidence collected breaks down by the three study motivations

total_atricles <- EIPAAB_database %>% 
  dplyr::distinct(article_id) %>% 
  nrow()

# Analyze the study motivations in the dataset
EIPAAB_database %>%
  dplyr::group_by(article_id) %>% # Group the data by 'article_id'
  dplyr::sample_n(1) %>% # Randomly sample one row from each group (i.e., each unique 'article_id')
  dplyr::ungroup() %>% # Ungroup the data to remove the previous grouping
  dplyr::group_by(study_motivation) %>% # Group the data by 'study_motivation'
  dplyr::reframe( # Create a summary data frame with the count and percentage of each study motivation
    n = length(study_motivation),  # Count the number of occurrences of each study motivation
    `%` = round(n / total_atricles, 3) * 100  # Calculate the percentage of total articles
  ) %>% 
  dplyr::arrange(desc(n)) # Arrange the resulting data frame in descending order of the count
## # A tibble: 3 × 3
##   study_motivation     n   `%`
##   <chr>            <int> <dbl>
## 1 Environmental      510  56.6
## 2 Medical            234  26  
## 3 Basic research     157  17.4

Here we are changing the order of these in the database to “Environmental”, “Medical”, “Basic research” for plots.

EIPAAB_database <- EIPAAB_database %>%
    dplyr::mutate(study_motivation = fct_relevel(study_motivation, "Environmental",
        "Medical", "Basic research"))

10 Publications by year

10.1 Number per year

Year range is 1974 to 2022, so 48 years worth of empirical research has contributed to this evidence base.

EIPAAB_database %>%
    dplyr::reframe(min_year = min(year), max_year = max(year), total_years = max_year -
        min_year)
##   min_year max_year total_years
## 1     1974     2022          48

Now making a summary for the number of publications per year based on study motivation

# Create a complete sequence of years and all unique study motivations
all_years <- as.character(1974:2022)
all_study_motivations <- unique(EIPAAB_database$study_motivation)

# Create a data frame with all combinations of year and study motivation
all_combinations <- expand.grid(year = all_years, study_motivation = all_study_motivations,
    stringsAsFactors = FALSE)

# Summarize the data
pub_year <- EIPAAB_database %>%
    group_by(year, study_motivation) %>%
    summarize(n = length(unique(article_id)), .groups = "drop") %>%
    mutate(year = as.character(year))

# Join with the complete grid of years and study motivations
pub_year_complete <- all_combinations %>%
    left_join(pub_year, by = c("year", "study_motivation")) %>%
    mutate(n = if_else(is.na(n), 0, n), year = as.numeric(year))

Here’s a summary figure for the manuscript (MS).

# Define the colour palette
motivation_colour_theme <- c("#60BD6C", "#D359A1", "#3C82C4") # Making colour theme to apply to plot

# Create the plot
pub_year_fig <- pub_year_complete %>%
  # Group years before 1996 and reformat the year column
  dplyr::mutate(
    year = as.character(if_else(year < 1996, 1996, year)), # Grouping years before 1996
    year = if_else(year == "1996", "<1997", year)          # Renaming 1995 group to "<1996"
  ) %>%
  # Creating the plot
  ggplot(aes(y = n, x = year, fill = study_motivation)) +
  geom_bar(stat = "identity", width = 0.9) +
  # Apply the custom colours
  scale_fill_manual(values = motivation_colour_theme, name = "Study motivation") + 
  theme_classic() +
  # Customizing the theme
  theme(
    legend.position = c(0.05, 1), # Positioning the legend in the top-left corner within the plot
    legend.justification = c(0, 1), # Ensuring the legend box aligns properly at the top-left corner
    axis.text.x = element_text(angle = 90, vjust = 0.5) # Rotating x-axis labels for better readability
  ) +
  # Adding axis labels
  labs(
    x = "Year of publication",
    y = "Number of articles"
  )

# Display the plot
pub_year_fig

Saving the figure as a PDF

setwd(figures_path)
# ggsave('pub_year_fig.png', plot = pub_year_fig, width = 10, height = 5, dpi =
# 300) #if you want to save a png
ggsave("study_pub_year_fig.pdf", plot = pub_year_fig, width = 10, height = 5)

10.2 Cumulative and relative growth

Making values for cumulative and relative growth in articles. This is the cumulative number of articles per year for each study moitvation, as well as the relative growth based on 2007. We selected 2007 for a 15 year overview in growth.

pub_year_growth <- pub_year_complete %>%
  dplyr::group_by(study_motivation) %>%
  dplyr::mutate(
    n_cumulative = cumsum(n),  # Calculate the cumulative sum of 'n'
    n_cumulative_prop = n_cumulative / max(n_cumulative), # Calculate the cumulative proportion
    n_2007 = ifelse(year == 2007, n, NA_real_), # Get n value for year 2007
    n_2007 = first(na.omit(n_2007)), # Propagate the n_2012 value within the group
    n_ratio_to_2007 = n / n_2007 # Calculate number of articles relative to that of 2007
  ) %>%
  dplyr::ungroup() %>%
  dplyr::select(study_motivation, year, n, n_cumulative, n_cumulative_prop, n_ratio_to_2007)

Making a plot for each motivation cumulative growth since 1974 (the first identified study)

cumulative_articles_fig <- pub_year_growth %>% 
  ggplot(aes(y = n_cumulative, x = year, colour = study_motivation)) +
  geom_line(stat = "identity", linewidth = 1.5) +
  geom_hline(yintercept = 0) +
  scale_x_continuous(breaks = seq(1974, 2022, by = 1)) +
  scale_colour_manual(values = motivation_colour_theme, name = "Study motivation") +
  theme_classic() +
  # Customizing the theme
  theme(
    legend.position = c(0.05, 1), # Positioning the legend in the top-left corner within the plot
    legend.justification = c(0, 1), # Ensuring the legend box aligns properly at the top-left corner
    axis.text.x = element_text(angle = 90, vjust = 0.5) # Rotating x-axis labels for better readability
  ) +
  # Adding axis labels
  labs(
    x = "Year of publication",
    y = "Articles cumulative growth"
  )

cumulative_articles_fig

setwd(figures_path)
ggsave("study_cumulative_articles_fig.pdf", plot = cumulative_articles_fig, width = 10,
    height = 5)

10.3 Reltive growth

Let’s look at relative growth compared to the research area more broadly

I will identify the most common research area based on each study motivation.

Environmental motivation = Environmental Sciences & Ecology Medical motivation = Neurosciences & Neurology Basic research = Neurosciences & Neurology

EIPAAB_database %>%
    dplyr::group_by(article_id) %>%
    dplyr::sample_n(1) %>%
    dplyr::ungroup() %>%
    dplyr::group_by(study_motivation, wos_research_areas) %>%
    dplyr::reframe(n = length(doi)) %>%
    dplyr::mutate(wos_research_areas = str_trim(wos_research_areas)) %>%
    tidyr::separate_rows(wos_research_areas, sep = ";") %>%
    dplyr::mutate(wos_research_areas = str_trim(wos_research_areas)) %>%
    dplyr::group_by(study_motivation, wos_research_areas) %>%
    dplyr::reframe(n_total = sum(n)) %>%
    dplyr::arrange(desc(n_total)) %>%
    dplyr::arrange(study_motivation) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::slice(1:2) %>%
    dplyr::ungroup()
## # A tibble: 6 × 3
##   study_motivation wos_research_areas               n_total
##   <fct>            <chr>                              <int>
## 1 Environmental    Environmental Sciences & Ecology     321
## 2 Environmental    Toxicology                           193
## 3 Medical          Neurosciences & Neurology            106
## 4 Medical          Pharmacology & Pharmacy               72
## 5 Basic research   Neurosciences & Neurology             56
## 6 Basic research   Behavioral Sciences                   43

We will now compare the proportion cumulative growth of each study motivation against the most common research areas based on WoS.

I have searched articles published within these research areas from 1992-2022, and create a database to compare against.

Each search indued only a date range (e.g. PY=(1992-2021)) AND the given web of science resarch area (e.g. WC=(Pharmacology & Pharmacy)). Searchers were done on the 04/07/2024. Only the total number of articles each year was taken.

First we will import the research field annual number of articles database I create (martin-et-al-supp-file-9-wos-research-areas-1992-2022.csv). It is provide as supplementary file 9.

setwd(input_path)

wos_research_areas_n <- read.csv("martin-et-al-supp-file-9-wos-research-areas-1992-2022.csv") %>% 
  dplyr::arrange(year) %>%
  dplyr::group_by(research_area) %>%
  dplyr::mutate(
    n_cumulative = cumsum(n),  # Calculate the cumulative sum of 'n'
    n_cumulative_prop = n_cumulative / max(n_cumulative), # Calculate the cumulative proportion
    n_2007 = ifelse(year == 2007, n, NA_real_), # Get n value for year 2011
    n_2007= first(na.omit(n_2007)), # Propagate the n_2011 value within the group
    n_ratio_to_2007 = n / n_2007 # Calculate n_ratio_to_2000
  ) %>%
  dplyr::ungroup() %>%
  dplyr::select(research_area, year, n, n_cumulative, n_cumulative_prop, n_ratio_to_2007)

Combined the number of articles with those in the EIPAAB database

pub_year_growth_comp <- pub_year_growth %>%
    dplyr::rename(research_area = study_motivation)

wos_research_areas_comp <- wos_research_areas_n %>%
    rbind(., pub_year_growth_comp) %>%
    dplyr::mutate(research_area = factor(research_area, levels = c("Environmental",
        "Medical", "Basic research", "Environmental Sciences and Ecology", "Toxicology",
        "Neurosciences and Neurology", "Pharmacology and Pharmacy", "All Research Areas")))

Let’s see what the relative growth was in 2022 (the latest included year in the evidence base)

wos_research_areas_comp %>%
    dplyr::filter(year == 2022)
## # A tibble: 8 × 6
##   research_area       year      n n_cumulative n_cumulative_prop n_ratio_to_2007
##   <fct>              <dbl>  <dbl>        <dbl>             <dbl>           <dbl>
## 1 Pharmacology and …  2022 8.04e4      1458833                 1            1.77
## 2 Neurosciences and…  2022 2.44e4       450515                 1            1.60
## 3 Toxicology          2022 1.69e4       391858                 1            1.41
## 4 Environmental Sci…  2022 4.60e3       103123                 1            1.07
## 5 All Research Areas  2022 3.62e6     66839129                 1            1.79
## 6 Environmental       2022 5.7 e1          510                 1           19   
## 7 Medical             2022 3   e1          234                 1           10   
## 8 Basic research      2022 9   e0          158                 1            2.25

10.3.1 Enviormental relative growth

Let’s now compare the relative growth in Environmental research

# Define the colour palette
env_colour_theme <- c("#60BD6C", "#2E4B22", "black") # Making colour theme to apply to plot

enviro_comp <-  c("Environmental", "Environmental Sciences and Ecology", "All Research Areas")

line_types <- c("Environmental" = "solid", 
                "Environmental Sciences and Ecology" = "dashed", 
                "All Research Areas" = "solid")

relative_growth_env_fig <- wos_research_areas_comp %>% 
  dplyr::filter(research_area %in% enviro_comp, year > 2006) %>% 
  ggplot(aes(y = n_ratio_to_2007, x = year, colour = research_area, linetype = research_area)) +
  geom_line(stat = "identity", linewidth = 1.5) +
  scale_x_continuous(breaks = seq(2007, 2022, by = 1)) +
  scale_y_continuous(limits = c(0, 22), breaks = seq(0, 22, by = 4)) + # Scale Y axis from 0 to 22
  scale_colour_manual(values = env_colour_theme, name = "Research Area") +
  scale_linetype_manual(values = line_types) + # Apply manual line types
  guides(linetype = "none") + # Remove legend for line types
  theme_classic() +
  # Customizing the theme
  theme(
    legend.position = c(0.05, 1), # Positioning the legend in the top-left corner within the plot
    legend.justification = c(0, 1), # Ensuring the legend box aligns properly at the top-left corner
    axis.text.x = element_text(angle = 90, vjust = 0.5) # Rotating x-axis labels for better readability
  ) +
  # Adding axis labels
  labs(
    x = "Year of publication",
    y = "Relative growth compared to 2007 (15 year baseline)"
  )

relative_growth_env_fig

setwd(figures_path)
ggsave("study_relative_growth_env_fig.pdf", plot = relative_growth_env_fig, width = 5,
    height = 5)

10.3.2 Medical relative growth

Comparing the relative growth in medical research

# Define the colour palette
med_colour_theme <- c("#D359A1", "#D2137F", "black") # Making colour theme to apply to plot

med_comp <-  c("Medical", "Neurosciences and Neurology", "All Research Areas")

line_types <- c("Medical" = "solid", 
                "Neurosciences and Neurology" = "dashed", 
                "All Research Areas" = "solid")

relative_growth_med_fig <- wos_research_areas_comp %>% 
  dplyr::filter(research_area %in% med_comp, year > 2006) %>% 
  ggplot(aes(y = n_ratio_to_2007, x = year, colour = research_area, linetype = research_area)) +
  geom_line(stat = "identity", linewidth = 1.5) +
  scale_x_continuous(breaks = seq(2007, 2022, by = 1)) +
  scale_y_continuous(limits = c(0, 22), breaks = seq(0, 22, by = 4)) + # Scale Y axis from 0 to 22
  scale_colour_manual(values = med_colour_theme, name = "Research Area") +
  scale_linetype_manual(values = line_types) + # Apply manual line types
  guides(linetype = "none") + # Remove legend for line types
  theme_classic() +
  # Customizing the theme
  theme(
    legend.position = c(0.05, 1), # Positioning the legend in the top-left corner within the plot
    legend.justification = c(0, 1), # Ensuring the legend box aligns properly at the top-left corner
    axis.text.x = element_text(angle = 90, vjust = 0.5) # Rotating x-axis labels for better readability
  ) +
  # Adding axis labels
  labs(
    x = "Year of publication",
    y = "Relative growth compared to 2007 (15 year baseline)"
  )

relative_growth_med_fig

setwd(figures_path)
ggsave("study_relative_growth_med_fig.pdf", plot = relative_growth_med_fig, width = 5,
    height = 5)

10.3.2 Basic resarch relative growth

Comparing relative growth in basic research

# Define the colour palette
basic_colour_theme <- c("#3C82C4", "#26276D", "black") # Making colour theme to apply to plot

basic_comp <-  c("Basic research", "Neurosciences and Neurology", "All Research Areas")

line_types <- c("Basic research" = "solid", 
                "Neurosciences and Neurology" = "dashed", 
                "All Research Areas" = "solid")

relative_growth_base_fig <- wos_research_areas_comp %>% 
  dplyr::filter(research_area %in% basic_comp, year > 2006) %>% 
  ggplot(aes(y = n_ratio_to_2007, x = year, colour = research_area, linetype = research_area)) +
  geom_line(stat = "identity", linewidth = 1.5) +
  scale_x_continuous(breaks = seq(2007, 2022, by = 1)) +
  scale_y_continuous(limits = c(0, 22), breaks = seq(0, 22, by = 4)) + # Scale Y axis from 0 to 22
  scale_colour_manual(values = basic_colour_theme, name = "Research Area") +
  scale_linetype_manual(values = line_types) + # Apply manual line types
  guides(linetype = "none") + # Remove legend for line types
  theme_classic() +
  # Customizing the theme
  theme(
    legend.position = c(0.05, 1), # Positioning the legend in the top-left corner within the plot
    legend.justification = c(0, 1), # Ensuring the legend box aligns properly at the top-left corner
    axis.text.x = element_text(angle = 90, vjust = 0.5) # Rotating x-axis labels for better readability
  ) +
  # Adding axis labels
  labs(
    x = "Year of publication",
    y = "Relative growth compared to 2007 (15 year baseline)"
  )

relative_growth_base_fig

setwd(figures_path)
ggsave("study_relative_growth_base_fig.pdf", plot = relative_growth_base_fig, width = 5,
    height = 5)

11 Population, Exposure and Outcome

Looking at the link between the PEO elements. What was the average study design.

Below I have made a table that groups by these elements to see the average study design

It was 1 compound, 1 species and 1 behavioural class (41%)

behav_boolean <- c("behav_movement_boolean", "behav_boldness_boolean", "behav_foraging_boolean", "behav_antipredator_boolean", "behav_mating_boolean", "behav_post_mating_boolean", "behav_agression_boolean", "behav_sociality_boolean", "behav_cognition_boolean", "behav_noncat_boolean")

EIPAAB_database %>%
  dplyr::mutate(behav_n = rowSums(across(all_of(behav_boolean)), na.rm = TRUE)) %>% # how many behav class measured
  dplyr::group_by(article_id) %>% 
  dplyr::arrange(desc(behav_n)) %>% 
  dplyr::slice(1) %>% 
  dplyr::ungroup() %>% 
  dplyr::select(compound_n, species_n, behav_n) %>% 
  dplyr::group_by(compound_n, species_n, behav_n) %>% 
  dplyr::reframe(n= length(compound_n),
                 '%' = round(n/902*100,1)) %>% 
  dplyr::arrange(desc(n))
## # A tibble: 45 × 5
##    compound_n species_n behav_n     n   `%`
##         <int>     <int>   <dbl> <int> <dbl>
##  1          1         1       1   374  41.5
##  2          1         1       2   160  17.7
##  3          2         1       1    78   8.6
##  4          1         1       3    63   7  
##  5          3         1       1    45   5  
##  6          2         1       2    34   3.8
##  7          4         1       1    24   2.7
##  8          3         1       2    15   1.7
##  9          1         2       1    13   1.4
## 10          5         1       1     9   1  
## # ℹ 35 more rows

I summary df that has the number of PEO elements in each of the 901 studies

PEO_element_summary <- EIPAAB_database %>%
    dplyr::mutate(behav_n = rowSums(across(all_of(behav_boolean)), na.rm = TRUE)) %>%
    dplyr::group_by(article_id) %>%
    dplyr::arrange(desc(behav_n)) %>%
    dplyr::slice(1) %>%
    dplyr::ungroup() %>%
    dplyr::select(compound_n, species_n, behav_n)

Looking at the number of species used

PEO_element_summary %>%
    dplyr::group_by(species_n) %>%
    dplyr::reframe(n = length(species_n), `%` = n/901)
## # A tibble: 5 × 3
##   species_n     n     `%`
##       <int> <int>   <dbl>
## 1         1   873 0.969  
## 2         2    25 0.0277 
## 3         3     1 0.00111
## 4         4     1 0.00111
## 5         5     1 0.00111

Looking at the number of compounds used

PEO_element_summary %>%
    dplyr::group_by(compound_n) %>%
    dplyr::reframe(n = length(compound_n), `%` = n/901)
## # A tibble: 18 × 3
##    compound_n     n     `%`
##         <int> <int>   <dbl>
##  1          1   624 0.693  
##  2          2   127 0.141  
##  3          3    67 0.0744 
##  4          4    32 0.0355 
##  5          5    16 0.0178 
##  6          6     8 0.00888
##  7          7     6 0.00666
##  8          8     5 0.00555
##  9          9     1 0.00111
## 10         10     2 0.00222
## 11         11     3 0.00333
## 12         12     2 0.00222
## 13         13     2 0.00222
## 14         14     2 0.00222
## 15         16     1 0.00111
## 16         18     1 0.00111
## 17         25     1 0.00111
## 18         52     1 0.00111
PEO_element_summary %>%
    dplyr::group_by(behav_n) %>%
    dplyr::reframe(n = length(species_n), `%` = n/901)
## # A tibble: 6 × 3
##   behav_n     n     `%`
##     <dbl> <int>   <dbl>
## 1       1   583 0.647  
## 2       2   227 0.252  
## 3       3    78 0.0866 
## 4       4    10 0.0111 
## 5       5     2 0.00222
## 6       7     1 0.00111

12 Species

Let’s take a closer look at species information

12.1 Number of distict species

There are 173 species in the EIPAAB database

EIPAAB_database %>%
    dplyr::distinct(species_name) %>%
    nrow()
## [1] 173

The number of spp each study motivation

EIPAAB_database %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::reframe(n_spp = length(unique(species_name)), total_study = length(unique(article_id)),
        rel_n = n_spp/total_study)
## # A tibble: 3 × 4
##   study_motivation n_spp total_study rel_n
##   <fct>            <int>       <int> <dbl>
## 1 Environmental      143         510 0.280
## 2 Medical             26         234 0.111
## 3 Basic research      43         158 0.272

There are 21 class

EIPAAB_database %>%
    dplyr::distinct(species_class) %>%
    nrow()
## [1] 21

There are 935 different groups of animals used across all 901 studies (i.e. some studies had more then one species)

EIPAAB_database %>%
    dplyr::distinct(unique_population_id) %>%
    nrow(.)
## [1] 935

12.2 Major taxa groups

12.2.1 Cladogram (Taxonomic tree)

Let’s make a Cladogram to get an overview of what taxa are in the database

spp_taxonomy <- EIPAAB_database %>%
    dplyr::group_by(species_name) %>%
    dplyr::sample_n(1) %>%
    dplyr::ungroup() %>%
    dplyr::filter(!is.na(species_family), !str_detect(species_species, "spp."), species_kingdom !=
        "Chromista") %>%
    dplyr::select("species_kingdom", "species_phylum", "species_class", "species_order",
        "species_family", "species_genus", "species_species") %>%
    dplyr::mutate(species_species = paste0(substr(species_genus, 1, 1), ". ", sub("^[^ ]+ ",
        "", species_species)))
# The mutate changes the spp name to abbreviate the Genus (e.g. Aeshna cyanea
# to A. cyanea)

Create a hierarchical structure for the plot

taxonomy <- spp_taxonomy[, c("species_kingdom", "species_phylum", "species_class",
    "species_order", "species_family", "species_genus", "species_species")]

taxonomy[] <- lapply(taxonomy, factor)

# Create a phylogenetic tree
phylo_tree <- as.phylo.formula(~species_kingdom/species_phylum/species_class/species_order/species_family/species_genus/species_species,
    data = taxonomy)

Manual creating a phylo_tree (with equal branches)

ggtree_obj <- ggtree(phylo_tree, branch.length='none', layout='circular')

# Extract the phylum information for coloring
#taxonomy$label <- paste0(substr(spp_taxonomy$species_genus, 1, 1), ". ", spp_taxonomy$species_species)
class_info <- taxonomy$species_class[match(phylo_tree$tip.label, taxonomy$species_species)]

# Add the phylum information to the ggtree object
ggtree_obj <- ggtree_obj %<+% data.frame(label = phylo_tree$tip.label, class = class_info)

# Create a color vector for the phylum levels
class_colors <- rainbow(length(unique(class_info)))
names(class_colors) <- unique(class_info)

# Plot the cladogram with colored branches
spp_cladogram <- ggtree_obj +
  geom_tiplab(size=3) + #If you want to add species names
  geom_tree(aes(color=class)) +
  scale_color_manual(values = class_colors) +
  theme(legend.position = "right")
spp_cladogram

setwd(figures_path)
ggsave("spp_cladogram.pdf", plot = spp_cladogram, width = 8, height = 5)

12.2.2 Class level

Let’s group by class to see the major taxonomic Classes used

First removing cases where species_species was “spp.” replacing with NA for taxonomic classification

EIPAAB_database <- EIPAAB_database %>%
    dplyr::mutate(species_species = if_else(species_species == "spp.", NA, species_species))

Let’s look at the major Class

# Total number of spp
n_spp <- EIPAAB_database %>%
    dplyr::distinct(species_name) %>%
    nrow()

# Number of spp per Class and per phylum
spp_classes <- EIPAAB_database %>%
    dplyr::group_by(species_class, species_phylum) %>%
    dplyr::reframe(count_class = length(unique(species_name)), percent_class = round(count_class/n_spp *
        100, 1)) %>%
    dplyr::group_by(species_phylum) %>%
    dplyr::mutate(count_phylum = sum(count_class), percent_phylum = round(count_phylum/n_spp *
        100, 1)) %>%
    dplyr::ungroup() %>%
    dplyr::arrange(desc(percent_class))


spp_classes %>%
    dplyr::slice(1:10)
## # A tibble: 10 × 6
##    species_class  species_phylum  count_class percent_class count_phylum
##    <chr>          <chr>                 <int>         <dbl>        <int>
##  1 Actinopterygii Chordata                 71          41             87
##  2 Malacostraca   Arthropoda               21          12.1           42
##  3 Gastropoda     Mollusca                 19          11             28
##  4 Amphibia       Chordata                 12           6.9           87
##  5 Branchiopoda   Arthropoda               10           5.8           42
##  6 Bivalvia       Mollusca                  8           4.6           28
##  7 Insecta        Arthropoda                8           4.6           42
##  8 Rhabditophora  Platyhelminthes           5           2.9            6
##  9 Reptilia       Chordata                  3           1.7           87
## 10 Copepoda       Arthropoda                2           1.2           42
## # ℹ 1 more variable: percent_phylum <dbl>

Making a figure for the 15 most abundant Class, it terms of species diversity in the EIPAAB database

class_n_spp_fig <- spp_classes %>% 
  dplyr::arrange(desc(percent_class)) %>% # arrange the dataset
  dplyr::slice(1:15) %>% # Take only the most diverse 15 Class
  dplyr::mutate(species_class = fct_reorder(species_class, percent_class), # Order by diversity
                species_phylum = fct_reorder(species_phylum, desc(percent_phylum))) %>% # Order by diversity
  ggplot(aes(x=species_class, y=count_class, color = species_phylum)) +
  geom_segment(aes(x=species_class, xend=species_class, y=0, yend=count_class)) +
  geom_point(size=4) +
  geom_text(aes(label = count_class), 
            hjust=-1.2, 
            size=3.5, 
            color="black") +
  scale_colour_brewer(palette= "Dark2") +
  coord_flip() +
  ylim(0, 75) +
  theme_classic() +
   labs(
    x = "",
    y = "Number of distict species in the database"
  ) +
   theme(legend.position = c(0., 0.05),  # Positioning the legend inside the plot
    legend.justification = c(-3, 0),   # Bottom left inside the plot
    legend.box.just = "right",
    legend.background = element_rect(fill=alpha('white', 0.5))
   )

class_n_spp_fig

Save the figure

setwd(figures_path)
ggsave("spp_class_n_spp_fig.pdf", plot = class_n_spp_fig, width = 5, height = 5)

12.2.3 Phylum level

Here’s a look at the % at the phylum level

# In the class summary we also included percent_phylum
spp_classes %>%
    dplyr::group_by(species_phylum) %>%
    dplyr::sample_n(1) %>%
    dplyr::ungroup() %>%
    dplyr::select(-species_class, -count_class, -percent_class) %>%
    dplyr::arrange(desc(percent_phylum))
## # A tibble: 8 × 3
##   species_phylum  count_phylum percent_phylum
##   <chr>                  <int>          <dbl>
## 1 Chordata                  87           50.3
## 2 Arthropoda                42           24.3
## 3 Mollusca                  28           16.2
## 4 Platyhelminthes            6            3.5
## 5 Annelida                   3            1.7
## 6 Echinodermata              3            1.7
## 7 Cnidaria                   2            1.2
## 8 Rotifera                   2            1.2

A ring chart at the phylum level

ring_plot_df <- spp_classes %>%
    dplyr::slice(1:15) %>%
    dplyr::group_by(species_phylum) %>%
    dplyr::sample_n(1) %>%
    dplyr::ungroup() %>%
    dplyr::select(species_phylum, count_phylum) %>%
    dplyr::mutate(percent_phylum = count_phylum/sum(count_phylum)) %>%
    dplyr::arrange(desc(percent_phylum))

# Compute the cumulative percentages (top of each rectangle)
ring_plot_df$ymax = cumsum(ring_plot_df$percent_phylum)

# Compute the bottom of each rectangle
ring_plot_df$ymin = c(0, head(ring_plot_df$ymax, n = -1))

# Compute label position
ring_plot_df$labelPosition <- (ring_plot_df$ymax + ring_plot_df$ymin)/2

# Compute a good label
ring_plot_df$label <- paste0(ring_plot_df$species_phylum, "\n (n = ", ring_plot_df$count_phylum,
    ")")


phylum_ring_fig <- ring_plot_df %>%
    dplyr::mutate(species_phylum = fct_reorder(species_phylum, desc(percent_phylum))) %>%
    ggplot(aes(ymax = ymax, ymin = ymin, xmax = 4, xmin = 3, fill = species_phylum)) +
    geom_rect() + coord_polar(theta = "y") + geom_label(x = 5, aes(y = labelPosition,
    label = label), size = 3, alpha = 0.8) + scale_fill_brewer(palette = "Dark2") +
    xlim(c(2, 5)) + theme_void() + theme(legend.position = "none")

phylum_ring_fig

setwd(figures_path)
ggsave("spp_phylum_ring_fig.pdf", plot = phylum_ring_fig, width = 5, height = 5)

12.3 Taxa representation

Now we will look at how many times each phylum, class, order, family, genus, species appear in the database

First we will make a dataset that counts the number of species within each phylum, class, order, family, and genus.

# Step 1: Separate and pivot the data
lineage_data <- EIPAAB_database %>%
    pivot_longer(cols = c("species_phylum", "species_class", "species_order", "species_family",
        "species_genus", "species_species"), names_to = "lineage_level", values_to = "classification") %>%
    dplyr::mutate(lineage_level = str_remove(lineage_level, "species_"))


# Define the order
lineage_levels_order <- c("phylum", "class", "order", "family", "genus", "species")

# Step 2: Create parent-child relationships
lineage_data <- lineage_data %>%
    group_by(unique_row_id) %>%
    mutate(parent = case_when(lineage_level == "phylum" ~ "Animalia", lineage_level ==
        "class" ~ lag(classification, 1), lineage_level == "order" ~ lag(classification,
        1), lineage_level == "family" ~ lag(classification, 1), lineage_level ==
        "genus" ~ lag(classification, 1), lineage_level == "species" ~ lag(classification,
        1), )) %>%
    ungroup()

Here we sum the total number of species used in the database across each taxonomic classification

n_rows <- EIPAAB_database %>%
    nrow()

lineage_count_use <- lineage_data %>%
    dplyr::group_by(classification, lineage_level, parent) %>%
    dplyr::reframe(classification_count = length(unique_row_id), classification_percent = round(classification_count/n_rows *
        100, 1))

Making a plot to look at the 15 most commonly used class, but you can do this at any of the taxonomic levels

class_use_fig <- lineage_count_use %>% 
  dplyr::filter(lineage_level == "class") %>% 
  dplyr::arrange(desc(classification_percent)) %>% 
  dplyr::slice(1:15) %>% 
  dplyr::mutate(classification = fct_reorder(classification, classification_percent),
                parent = fct_reorder(parent, desc(classification_percent))) %>%
  ggplot(aes(x=classification, y=classification_percent, color = parent)) +
  geom_segment(aes(x=classification, xend=classification, y=0, yend=classification_percent)) +
  geom_point(size=4) +
  geom_text(aes(label = paste0(round(classification_percent,2), "%")), 
            hjust=-0.5, 
            size=3.5, 
            color="black") +
  scale_colour_brewer(palette= "Dark2") +
  coord_flip() +
  ylim(0, 100) +
  theme_classic() +
   labs(
    x = "",
    y = "Percentage representation in the database"
  ) +
   theme(legend.position = c(0., 0.05),  # Positioning the legend inside the plot
    legend.justification = c(-3, 0),   # Bottom left inside the plot
    legend.box.just = "right",
    legend.background = element_rect(fill=alpha('white', 0.5))
   )

class_use_fig

setwd(figures_path)
ggsave("spp_class_use_fig.pdf", plot = class_use_fig, width = 5, height = 5)
lineage_count_use %>%
    dplyr::filter(lineage_level == "class") %>%
    dplyr::group_by(classification) %>%
    dplyr::sample_n(1) %>%
    dplyr::ungroup() %>%
    dplyr::arrange(desc(classification_percent))
## # A tibble: 21 × 5
##    classification lineage_level parent          classification_count
##    <chr>          <chr>         <chr>                          <int>
##  1 Actinopterygii class         Chordata                        1312
##  2 Branchiopoda   class         Arthropoda                       130
##  3 Gastropoda     class         Mollusca                          69
##  4 Malacostraca   class         Arthropoda                        61
##  5 Amphibia       class         Chordata                          44
##  6 Rhabditophora  class         Platyhelminthes                   29
##  7 Bivalvia       class         Mollusca                          25
##  8 Hydrozoa       class         Cnidaria                          22
##  9 Insecta        class         Arthropoda                        17
## 10 Cephalopoda    class         Mollusca                           7
## # ℹ 11 more rows
## # ℹ 1 more variable: classification_percent <dbl>

Here’s break down by Phylum

ring_use_plot_df <- lineage_count_use %>%
    dplyr::filter(lineage_level == "phylum") %>%
    dplyr::arrange(desc(classification_percent)) %>%
    dplyr::mutate(classification_percent = round(classification_percent, 2)) %>%
    dplyr::slice(1:8)

# Compute the cumulative percentages (top of each rectangle)
ring_use_plot_df$ymax = cumsum(ring_use_plot_df$classification_percent)

# Compute the bottom of each rectangle
ring_use_plot_df$ymin = c(0, head(ring_use_plot_df$ymax, n = -1))

# Compute label position
ring_use_plot_df$labelPosition <- (ring_use_plot_df$ymax + ring_use_plot_df$ymin)/2

# Compute a good label
ring_use_plot_df$label <- paste0(ring_use_plot_df$classification, "\n (", ring_use_plot_df$classification_percent,
    "%)")


phylum_use_ring_fig <- ring_use_plot_df %>%
    dplyr::mutate(classification = fct_reorder(classification, desc(classification_percent))) %>%
    ggplot(aes(ymax = ymax, ymin = ymin, xmax = 4, xmin = 3, fill = classification)) +
    geom_rect() + coord_polar(theta = "y") + geom_label(x = 5, aes(y = labelPosition,
    label = label), size = 3, alpha = 0.8) + scale_fill_brewer(palette = "Dark2") +
    xlim(c(2, 5)) + theme_void()
# theme(legend.position = 'none')

phylum_use_ring_fig

setwd(figures_path)
ggsave("spp_phylum_use_ring_fig.pdf", plot = phylum_use_ring_fig, width = 5, height = 5)

12.3.2 Taxa representation by study motivation

Making a data set that looks at relative representation by each motivation, and the total

lineage_count_use_motivation <- lineage_data %>%
    dplyr::group_by(study_motivation, lineage_level, parent, classification) %>%
    dplyr::reframe(classification_count = length(unique_row_id)) %>%
    dplyr::group_by(study_motivation, lineage_level) %>%
    dplyr::mutate(n_motivation = sum(classification_count)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(classification_percent = (classification_count/n_motivation) *
        100)

lineage_count_use_all <- lineage_data %>%
    dplyr::group_by(lineage_level, parent, classification) %>%
    dplyr::reframe(classification_count = length(unique_row_id)) %>%
    dplyr::group_by(lineage_level) %>%
    dplyr::mutate(n_motivation = sum(classification_count)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(classification_percent = (classification_count/n_motivation) *
        100) %>%
    dplyr::mutate(study_motivation = "All")

lineage_count_use_motivation <- lineage_count_use_motivation %>%
    rbind(., lineage_count_use_all) %>%
    dplyr::mutate(study_motivation = fct_relevel(study_motivation, "All", "Environmental",
        "Medical", "Basic research"))

Here’s a tile plot to compare the use of different taxa across the study motivations

class_order_df <- lineage_count_use %>%
    dplyr::filter(lineage_level == "class") %>%
    dplyr::arrange(classification_percent) %>%
    dplyr::mutate(class_order = 1:nrow(.)) %>%
    dplyr::select(classification, class_order)


class_use_motivation_fig <- lineage_count_use_motivation %>%
    dplyr::filter(lineage_level == "class") %>%
    dplyr::full_join(., class_order_df, by = "classification") %>%
    dplyr::mutate(classification = fct_reorder(classification, class_order), parent = fct_reorder(parent,
        desc(class_order))) %>%
    ggplot(aes(x = study_motivation, y = classification, fill = classification_percent)) +
    geom_tile() + geom_text(aes(label = paste0(round(classification_percent, 1),
    "%"))) + scale_fill_gradient(name = expression("Relative\nabudance (%)"), low = "#FFFFFF",
    high = "#231F20") + theme_classic() + labs(x = "Study motivation", y = "Taxonomic class")
class_use_motivation_fig

setwd(figures_path)
ggsave("spp_class_use_motivation_fig.pdf", plot = class_use_motivation_fig, width = 5,
    height = 5)

12.3.3 Most common species

Let’s see what the most common species were. This is calculated at the population level (i.e. doesn’t count each species mutiple times if multiple compounds were used in a single article; unique_population_id)

n_total <- EIPAAB_database %>%
    dplyr::group_by(unique_population_id) %>%
    dplyr::sample_n(1) %>%
    dplyr::reframe(n = length(unique_population_id)) %>%
    nrow(.)

n_spp <- EIPAAB_database %>%
    dplyr::group_by(unique_population_id, species_ncbi_taxonomy_id) %>%
    dplyr::sample_n(1) %>%
    dplyr::ungroup() %>%
    dplyr::group_by(species_name, species_ncbi_taxonomy_id) %>%
    dplyr::reframe(n = length(species_name), percent = round(n/n_total * 100, 1)) %>%
    dplyr::arrange(desc(n)) %>%
    dplyr::mutate(spp_number = 1:nrow(.))

n_spp
## # A tibble: 173 × 5
##    species_name           species_ncbi_taxonomy_id     n percent spp_number
##    <chr>                  <chr>                    <int>   <dbl>      <int>
##  1 Danio rerio            NCBI:txid7955              412    44.1          1
##  2 Daphnia magna          NCBI:txid35525              54     5.8          2
##  3 Pimephales promelas    NCBI:txid90988              32     3.4          3
##  4 Betta splendens        NCBI:txid158456             26     2.8          4
##  5 Poecilia reticulata    NCBI:txid8081               26     2.8          5
##  6 Gambusia holbrooki     NCBI:txid37273              18     1.9          6
##  7 Carassius auratus      NCBI:txid7957               16     1.7          7
##  8 Oryzias latipes        NCBI:txid8090               16     1.7          8
##  9 Gasterosteus aculeatus NCBI:txid69293              14     1.5          9
## 10 Oncorhynchus mykiss    NCBI:txid8022               12     1.3         10
## # ℹ 163 more rows

Making a broad category of abundance (article_n_group) to make the summary and figure more digestible

n_spp_fig_data <- n_spp %>%
    dplyr::mutate(species_ncbi_taxonomy_id = fct_reorder(species_ncbi_taxonomy_id,
        desc(n))) %>%
    dplyr::mutate(article_n_group = case_when(n == 1 ~ "One only", n >= 2 & n <=
        5 ~ "Between 2 and 5", n >= 5 & n <= 10 ~ "Between 6 and 10", n >= 10 ~ "Greater than 10",
        TRUE ~ "Others"))

This is the number of species in each category

article_n_group_summary <- n_spp_fig_data %>%
    dplyr::group_by(article_n_group) %>%
    dplyr::reframe(n_cat = length(species_name))
article_n_group_summary
## # A tibble: 4 × 2
##   article_n_group  n_cat
##   <chr>            <int>
## 1 Between 2 and 5     53
## 2 Between 6 and 10     6
## 3 Greater than 10     11
## 4 One only           103

Making a plot to show the distribution of species use in the EIPAAB database

n_spp_fig <- n_spp_fig_data %>% 
  dplyr::mutate(article_n_group = fct_relevel(article_n_group, "Greater than 10", "Between 6 and 10", "Between 2 and 5", "One only")) %>% 
  ggplot(aes(y = n, x = spp_number, color = article_n_group)) +
  geom_line(linewidth = 1, alpha = 0.2) +
  geom_point(stat = "identity", size = 1, alpha = 0.8) +
  scale_color_manual(
    values = c(
    "One only" = "#E94039", 
    "Between 2 and 5" = "#F18E76", 
    "Between 6 and 10" = "#877FBC", 
    "Greater than 10" = "#4D479D"
    ),
  labels = c(
      "One only" = "One only (n = 104)",
      "Between 2 and 5" = "Between 2 and 5 (n = 53)",
      "Between 6 and 10" = "Between 6 and 10 (n = 11)",
      "Greater than 10" = "Greater than 10 (n = 6)"
      )
  ) +  # Set colours for each category
  theme_classic() +
  theme(
    legend.position = c(-0.3, 0.4),  # Positioning the legend inside the plot
    legend.justification = c(-3, 0),   # Bottom left inside the plot
    legend.box.just = "right"
    ) +
  labs(
    x = paste0("Species (1-174)"),
    y = "Number of articles",
    color = "Article number category"
  )

n_spp_fig

setwd(figures_path)
ggsave("spp_n_spp_fig.pdf", plot = n_spp_fig, width = 5, height = 5)

Making a list of the most common 15 species

n_spp_used <- EIPAAB_database %>%
    dplyr::distinct(unique_population_id) %>%
    nrow(.)

top_15_spp_list <- EIPAAB_database %>%
    dplyr::group_by(species_name) %>%
    dplyr::summarise(n = length(unique(unique_population_id)), .groups = "drop") %>%
    dplyr::arrange(desc(n)) %>%
    dplyr::slice(1:15) %>%
    dplyr::pull(species_name) %>%
    as.list()

Making a summary dataframe base on study motivation

common_species <- EIPAAB_database %>%
    dplyr::filter(species_name %in% top_15_spp_list) %>%
    dplyr::group_by(species_name, study_motivation) %>%
    dplyr::summarise(n = length(unique(article_id)), .groups = "drop") %>%
    tidyr::complete(species_name, study_motivation, fill = list(n = 0))


species_order <- common_species %>%
    group_by(species_name) %>%
    summarise(total_n = sum(n), .groups = "drop") %>%
    arrange(desc(total_n)) %>%
    ungroup()


common_species <- common_species %>%
    inner_join(species_order, by = "species_name") %>%
    mutate(species_name = fct_reorder(species_name, total_n), study_motivation = fct_relevel(study_motivation,
        "Environmental", "Medical", "Basic research"))

A plot of the number of times each of the 15 overall most common species appeared in articles within the EIPAAB databse by study motivation. It’s a little hard to see in the chunk output, try viewing in an external window.

top_15_spp_fig <- common_species %>%
    ggplot(aes(x = species_name, y = n, colour = study_motivation, fill = study_motivation,
        group = study_motivation)) + geom_col(position = position_dodge(width = 0.8),
    width = 0.1) + geom_point(position = position_dodge(width = 0.8), size = 3) +
    geom_text(aes(label = n), hjust = -0.6, size = 3.5, color = "black", position = position_dodge(width = 0.8)) +
    scale_colour_manual(values = motivation_colour_theme, name = "Study motivation") +
    scale_fill_manual(values = motivation_colour_theme, name = "Study motivation") +
    coord_flip() + theme_classic() + labs(x = "", y = "Number of studies") + theme()

top_15_spp_fig

setwd(figures_path)
ggsave("spp_top_15_spp_fig.pdf", plot = top_15_spp_fig, width = 5, height = 10)

Summarising the top 10 in each motivation more specifically

spp_moitivation_summary <- EIPAAB_database %>%
    dplyr::group_by(species_name, study_motivation) %>%
    dplyr::summarise(n = length(unique(unique_population_id)), .groups = "drop") %>%
    tidyr::complete(species_name, study_motivation, fill = list(n = 0)) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(prop = n/total) %>%
    dplyr::select(-total)

This plot shows the top 10 in each motivation

top_10_env_spp <- spp_moitivation_summary %>%
    dplyr::filter(study_motivation == "Environmental") %>%
    dplyr::arrange(desc(n)) %>%
    dplyr::slice(1:10) %>%
    dplyr::mutate(species_name = fct_reorder(species_name, n)) %>%
    ggplot(aes(x = species_name, y = n)) + geom_col(width = 0.01, colour = "#60BD6C",
    fill = "#60BD6C") + geom_point(size = 2, colour = "#60BD6C", fill = "#60BD6C") +
    geom_text(aes(label = n), hjust = -0.6, size = 3.5, color = "black") + coord_flip() +
    theme_classic() + labs(x = "", y = "Number of studies", title = "Environmental") +
    theme(plot.title = element_text(size = 12))

top_10_med_spp <- spp_moitivation_summary %>%
    dplyr::filter(study_motivation == "Medical") %>%
    dplyr::arrange(desc(n)) %>%
    dplyr::slice(1:10) %>%
    dplyr::mutate(species_name = fct_reorder(species_name, n)) %>%
    ggplot(aes(x = species_name, y = n)) + geom_col(width = 0.01, colour = "#D359A1",
    fill = "#D359A1") + geom_point(size = 2, colour = "#D359A1", fill = "#D359A1") +
    geom_text(aes(label = n), hjust = -0.6, size = 3.5, color = "black") + coord_flip() +
    theme_classic() + labs(x = "", y = "Number of studies", title = "Medical") +
    theme(plot.title = element_text(size = 12))

top_10_base_spp <- spp_moitivation_summary %>%
    dplyr::filter(study_motivation == "Basic research") %>%
    dplyr::arrange(desc(n)) %>%
    dplyr::slice(1:10) %>%
    dplyr::mutate(species_name = fct_reorder(species_name, n)) %>%
    ggplot(aes(x = species_name, y = n)) + geom_col(width = 0.01, colour = "#3C82C4",
    fill = "#3C82C4") + geom_point(size = 2, colour = "#3C82C4", fill = "#3C82C4") +
    geom_text(aes(label = n), hjust = -0.6, size = 3.5, color = "black") + coord_flip() +
    theme_classic() + labs(x = "", y = "Number of studies", title = "Basic") + theme(plot.title = element_text(size = 12))

Here’s a plot to compare the top 10 spp in each study motivation more specifically

top_10_combind_plot <- grid.arrange(top_10_env_spp, top_10_med_spp, top_10_base_spp,
    ncol = 3)

Looking at the number of distinct species used in each motivation group

EIPAAB_database %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::reframe(n_motivation = n_distinct(article_id), n_distinct_spp = n_distinct(species_name))
## # A tibble: 3 × 3
##   study_motivation n_motivation n_distinct_spp
##   <fct>                   <int>          <int>
## 1 Environmental             510            143
## 2 Medical                   234             26
## 3 Basic research            158             43

12.4 Species habitat

First checking how many species have IUCN data, which we will use to assess habitat differences

species_iucn_summary <- EIPAAB_database %>%
    dplyr::group_by(species_name) %>%
    dplyr::sample_n(1) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(species_iucn_bin = if_else(is.na(species_iucn_doi), "No", "Yes")) %>%
    dplyr::group_by(species_iucn_bin) %>%
    dplyr::reframe(n = length(species_iucn_bin))

species_iucn_summary
## # A tibble: 2 × 2
##   species_iucn_bin     n
##   <chr>            <int>
## 1 No                  67
## 2 Yes                106

Summarising the IUNC habitat type, some species will have multiple habitats, so we split the string by the sepreate (;)

habitat_summary <- EIPAAB_database %>% 
  dplyr::group_by(unique_population_id) %>% 
  dplyr::sample_n(1) %>% # sampling one row per article per species (i.e. ignoring multiple rows per article for compounds)
  dplyr::ungroup() %>% 
  dplyr::group_by(species_iucn_habitat) %>% 
  dplyr::reframe(n = n()) %>%
  dplyr::mutate(species_iucn_habitat = str_trim(species_iucn_habitat)) %>%
  tidyr::separate_rows(species_iucn_habitat, sep = ";") %>% # each spp has multiple habitats the string needs spliting
  dplyr::group_by(species_iucn_habitat) %>% 
  dplyr::reframe(n_articles = sum(n)) %>% # now a sum for each habitat
  arrange(desc(n_articles))
habitat_summary
## # A tibble: 13 × 2
##    species_iucn_habitat             n_articles
##    <chr>                                 <int>
##  1 Wetlands inland                         738
##  2 Artificial or Aquatic and Marine        187
##  3 <NA>                                    164
##  4 Marine Neritic                           99
##  5 Marine Coastal or Supratidal             44
##  6 Marine Intertidal                        27
##  7 Forest                                   23
##  8 Grassland                                22
##  9 Artificial or Terrestrial                21
## 10 Shrubland                                18
## 11 Savanna                                  13
## 12 Marine Oceanic                           10
## 13 Unknown                                   2

Checking how many freshwater vs marine species there are. Wetlands inland categories are freshwater bodies where as Marine have multiple categories (Marine Neritic, Marine Coastal or Supratidal, Marine Intertidal, Marine Oceanic).

habitat_summary %>% 
  dplyr::filter(str_starts(species_iucn_habitat, "Marine") | species_iucn_habitat == "Wetlands inland") %>% # Only habitats of interest 
  dplyr::mutate(aquatic_type = if_else(species_iucn_habitat == "Wetlands inland", "Freshwater", "Marine")) %>% # New category
  dplyr::group_by(aquatic_type) %>% 
  dplyr::reframe(n_articles = sum(n_articles)) %>% # Final sums
  dplyr::ungroup() %>% 
  dplyr::mutate(n_total = sum(n_articles),
                percent =  round(n_articles/n_total*100,1))
## # A tibble: 2 × 4
##   aquatic_type n_articles n_total percent
##   <chr>             <int>   <int>   <dbl>
## 1 Freshwater          738     918    80.4
## 2 Marine              180     918    19.6

Lets break this up by study motivation

habitat_summary_all <- EIPAAB_database %>% 
  dplyr::group_by(unique_population_id) %>% 
  dplyr::sample_n(1) %>% # sampling one row per article per species (i.e. ignoring multiple rows per article for compounds)
  dplyr::ungroup() %>% 
  dplyr::group_by(study_motivation, species_iucn_habitat) %>% 
  dplyr::reframe(n = n()) %>%
  dplyr::mutate(species_iucn_habitat = str_trim(species_iucn_habitat)) %>%
  tidyr::separate_rows(species_iucn_habitat, sep = ";") %>% # each spp has multiple habitats the string needs spliting
  dplyr::group_by(species_iucn_habitat, study_motivation) %>% 
  dplyr::reframe(n_articles = sum(n)) %>% # now a sum for each habitat
  arrange(desc(n_articles))
habitat_summary_all
## # A tibble: 37 × 3
##    species_iucn_habitat             study_motivation n_articles
##    <chr>                            <fct>                 <int>
##  1 Wetlands inland                  Environmental           384
##  2 Wetlands inland                  Medical                 223
##  3 Artificial or Aquatic and Marine Environmental           135
##  4 Wetlands inland                  Basic research          131
##  5 <NA>                             Environmental           131
##  6 Marine Neritic                   Environmental            80
##  7 Artificial or Aquatic and Marine Basic research           41
##  8 Marine Coastal or Supratidal     Environmental            33
##  9 <NA>                             Basic research           22
## 10 Marine Intertidal                Environmental            19
## # ℹ 27 more rows

Selecting only habitats of interest and allocating to Freshwater or Marine

freshwater_marine <- habitat_summary_all %>% 
  dplyr::filter(str_starts(species_iucn_habitat, "Marine") | species_iucn_habitat == "Wetlands inland") %>% # Only habitats of interest 
  dplyr::mutate(aquatic_type = if_else(species_iucn_habitat == "Wetlands inland", "Freshwater", "Marine")) %>% # New category
  dplyr::group_by(aquatic_type, study_motivation) %>% 
  dplyr::reframe(n_articles = sum(n_articles)) %>% # Final sums
  dplyr::group_by(study_motivation) %>% 
  dplyr::mutate(n_cat = sum(n_articles)) %>% 
  dplyr::ungroup() %>% 
  dplyr::mutate(prop =  n_articles/n_cat) # A proportion of those identify as freshwater vs marine

freshwater_marine
## # A tibble: 6 × 5
##   aquatic_type study_motivation n_articles n_cat   prop
##   <chr>        <fct>                 <int> <int>  <dbl>
## 1 Freshwater   Environmental           384   520 0.738 
## 2 Freshwater   Medical                 223   236 0.945 
## 3 Freshwater   Basic research          131   162 0.809 
## 4 Marine       Environmental           136   520 0.262 
## 5 Marine       Medical                  13   236 0.0551
## 6 Marine       Basic research           31   162 0.191
aquatic_type_order <- c("Freshwater", "Marine")

# Define the black and grey color theme color_theme <- c('#7FAB91', '#2A4A64')

# Calculate cumulative positions for text labels
freshwater_marine <- freshwater_marine %>%
    dplyr::mutate(aquatic_type = factor(aquatic_type, levels = aquatic_type_order)) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::arrange(desc(aquatic_type)) %>%
    dplyr::mutate(cumulative_prop = cumsum(prop) - prop/2)

# Define the black and grey color theme
color_theme <- c("#7FAB91", "#2A4A64")

# Create the plot
habitat_fig <- freshwater_marine %>%
    mutate(study_motivation = fct_relevel(study_motivation, "Basic research", "Medical",
        "Environmental")) %>%
    ggplot(aes(y = prop, x = study_motivation, fill = aquatic_type, group = aquatic_type)) +
    geom_bar(stat = "identity", width = 0.9) + geom_text(aes(label = round(prop,
    2), y = cumulative_prop), color = "white", size = 3) + scale_fill_manual(values = color_theme,
    name = "Habitat") + theme_classic() + theme(legend.position = "right") + labs(x = "Study motivation",
    y = "Proportion of all species assigned to freshwater or marine habitat") + coord_flip()

habitat_fig

setwd(figures_path)
ggsave("spp_habitat_fig.pdf", plot = habitat_fig, width = 10, height = 5)

We should also consider how many records did not inculde IUCN reports and thus habitat.

Let’s make a plot that shows how many didn’t have an assigned IUNC habitat. To add to the above figure.

no_habitat <- EIPAAB_database %>% 
  dplyr::group_by(unique_population_id) %>% 
  dplyr::sample_n(1) %>% # sampling one row per article per species (i.e. ignoring multiple rows per article for compounds)
  dplyr::ungroup() %>%
  dplyr::mutate(species_iucn_bin = if_else(is.na(species_iucn_doi), "No", "Yes")) %>% 
  dplyr::group_by(species_iucn_bin) %>% 
  dplyr::reframe(n = length(species_iucn_bin))
  

n_total <- EIPAAB_database %>% 
  dplyr::group_by(unique_population_id) %>% 
  dplyr::sample_n(1) %>% # sampling one row per article per species (i.e. ignoring multiple rows per article for compounds)
  dplyr::ungroup() %>%
  nrow(.)

no_habitat <- no_habitat %>%
  dplyr::mutate(prop = n/n_total)

no_habitat
## # A tibble: 2 × 3
##   species_iucn_bin     n  prop
##   <chr>            <int> <dbl>
## 1 No                 163 0.174
## 2 Yes                772 0.826

Here’s the plot

# Define the black and grey color theme
black_and_grey <- c("#BCBEC0", "#414042")

yes_order <- c("Yes", "No")

# Calculate cumulative positions for text labels
habitat_info_df_fig <- no_habitat %>%
  dplyr::mutate(species_iucn_bin = factor(species_iucn_bin, levels = yes_order)) %>% 
  dplyr::arrange(desc(species_iucn_bin)) %>% 
  dplyr::mutate(cumulative_prop = cumsum(prop) - prop / 2)

habitat_info_fig <- habitat_info_df_fig %>%
  dplyr::mutate(species_iucn_bin = factor(species_iucn_bin, levels = yes_order)) %>% 
  ggplot(aes(y = prop, x = 1, fill = species_iucn_bin)) +
  geom_bar(stat = "identity", width = 0.1) +
  geom_text(aes(label = round(prop, 2), y = cumulative_prop), color = "white") + 
  scale_fill_manual(values = black_and_grey, name = "Habitat") + 
  theme_classic() +
  theme(legend.position = "right",
        axis.text.x = element_blank(),  # Remove x-axis text
        axis.ticks.x = element_blank()  # Remove x-axis ticks 
        ) +
  labs(
    x = "",
    y = "Proportion of species tested in the database"
  )
habitat_info_fig

setwd(figures_path)
ggsave("spp_habitat_info_fig.pdf", plot = habitat_info_fig, width = 5, height = 10)

12.5 Species life satge

Let’s get an overall summary first, without Unknown or not specified life stages

EIPAAB_database %>% 
  dplyr::group_by(unique_population_id) %>% 
  dplyr::sample_n(1) %>% # sampling one row per article per species (i.e. ignoring multiple rows per article for compounds)
  dplyr::ungroup() %>% 
  dplyr::group_by(species_stage) %>% 
  dplyr::reframe(n = n()) %>%
  dplyr::mutate(species_stage = str_trim(species_stage)) %>%
  tidyr::separate_rows(species_stage, sep = ";") %>% # each spp has multiple habitats the string needs splitting
  dplyr::filter(species_stage != "Unknown or not specified") %>% 
  dplyr::group_by(species_stage) %>% 
  dplyr::reframe(n_articles = sum(n)) %>%  # now a sum for each habitat
  dplyr::mutate(total_stages = sum(n_articles)) %>% 
  dplyr::ungroup() %>% 
  dplyr::mutate(overall_percent = round(n_articles/total_stages*100,1))
## # A tibble: 4 × 4
##   species_stage n_articles total_stages overall_percent
##   <chr>              <int>        <int>           <dbl>
## 1 Adult                443          831            53.3
## 2 Egg or embryo         46          831             5.5
## 3 Juvenile             123          831            14.8
## 4 Larvae               219          831            26.4

Let’s take a look at spp life stages used in the EIPAAB databasebased on study motivation

stage_summary_all <- EIPAAB_database %>% 
  dplyr::group_by(unique_population_id) %>% 
  dplyr::sample_n(1) %>% # sampling one row per article per species (i.e. ignoring multiple rows per article for compounds)
  dplyr::ungroup() %>% 
  dplyr::group_by(study_motivation, species_stage) %>% 
  dplyr::reframe(n = n()) %>%
  dplyr::mutate(species_stage = str_trim(species_stage)) %>%
  tidyr::separate_rows(species_stage, sep = ";") %>% # each spp has multiple habitats the string needs splitting
  dplyr::group_by(species_stage, study_motivation) %>% 
  dplyr::reframe(n_total = sum(n)) %>%  # now a sum for each habitat
  dplyr::group_by(study_motivation) %>% 
  dplyr::mutate(n_motivation = sum(n_total)) %>% 
  dplyr::ungroup()

stage_summary_all
## # A tibble: 15 × 4
##    species_stage            study_motivation n_total n_motivation
##    <chr>                    <fct>              <int>        <int>
##  1 Adult                    Environmental        236          586
##  2 Adult                    Medical              135          246
##  3 Adult                    Basic research        72          165
##  4 Egg or embryo            Environmental         31          586
##  5 Egg or embryo            Medical               11          246
##  6 Egg or embryo            Basic research         4          165
##  7 Juvenile                 Environmental         92          586
##  8 Juvenile                 Medical               14          246
##  9 Juvenile                 Basic research        17          165
## 10 Larvae                   Environmental        127          586
## 11 Larvae                   Medical               64          246
## 12 Larvae                   Basic research        28          165
## 13 Unknown or not specified Environmental        100          586
## 14 Unknown or not specified Medical               22          246
## 15 Unknown or not specified Basic research        44          165

For life stages that are described, what is the breakdown

stage_order <- c("Adult", "Juvenile", "Larvae", "Egg or embryo")

# Define the black and grey color theme
color_theme <- c("#A14323", "#D86C2F", "#EE9E5A", "#F3E9A5")

# Making proportion for those that did report
stage_summary_described <- stage_summary_all %>%
    dplyr::filter(species_stage %in% stage_order) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(n_motivation = sum(n_total)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(prop = n_total/n_motivation)



# Calculate cumulative positions for text labels
stage_summary_described <- stage_summary_described %>%
    dplyr::mutate(species_stage = factor(species_stage, levels = stage_order)) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::arrange(desc(species_stage)) %>%
    dplyr::mutate(cumulative_prop = cumsum(prop) - prop/4)

# Create the plot
life_stage_fig <- stage_summary_described %>%
    mutate(study_motivation = fct_relevel(study_motivation, "Basic research", "Medical",
        "Environmental")) %>%
    ggplot(aes(y = prop, x = study_motivation, fill = species_stage, group = species_stage)) +
    geom_bar(stat = "identity", width = 0.9) + geom_text(aes(label = round(prop,
    2), y = cumulative_prop), color = "white", size = 3) + scale_fill_manual(values = color_theme,
    name = "Life stage") + theme_classic() + theme(legend.position = "right") + labs(x = "Study motivation",
    y = "Proportion of all species assigned to a life stage") + coord_flip()

life_stage_fig

setwd(figures_path)
ggsave("spp_life_stage_fig.pdf", plot = life_stage_fig, width = 10, height = 5)

Let’s also look at how many where unknown or not described

stage_summary_info <- stage_summary_all %>%
    dplyr::mutate(stage_reported = if_else(species_stage == "Unknown or not specified",
        "No", "Yes")) %>%
    dplyr::group_by(stage_reported) %>%
    dplyr::reframe(n = sum(n_total))

n_total <- stage_summary_info %>%
    dplyr::reframe(n_total = sum(n)) %>%
    pull(n_total)

stage_summary_info <- stage_summary_info %>%
    dplyr::mutate(prop = n/n_total)

Here’s the plot

# Define the black and grey color theme
black_and_grey <- c("#BCBEC0", "#414042")

yes_order <- c("Yes", "No")

# Calculate cumulative positions for text labels
stage_summary_info <- stage_summary_info %>%
  dplyr::mutate(stage_reported = factor(stage_reported, levels = yes_order)) %>% 
  dplyr::arrange(desc(stage_reported)) %>% 
  dplyr::mutate(cumulative_prop = cumsum(prop) - prop / 2)

stage_info_fig <- stage_summary_info %>%
  dplyr::mutate(stage_reported = factor(stage_reported, levels = yes_order)) %>% 
  ggplot(aes(y = prop, x = 1, fill = stage_reported)) +
  geom_bar(stat = "identity", width = 0.9) +
  geom_text(aes(label = round(prop, 2), y = cumulative_prop), color = "white") + 
  scale_fill_manual(values = black_and_grey, name = "Stage reported") + 
  theme_classic() +
  theme(legend.position = "right",
        axis.text.x = element_blank(),  # Remove x-axis text
        axis.ticks.x = element_blank()  # Remove x-axis ticks 
  ) +
  labs(
    x = "",
    y = "Proportion of species tested in the database"
  )
stage_info_fig

setwd(figures_path)
ggsave("spp_stage_info_fig.pdf", plot = stage_info_fig, width = 2.5, height = 5)

12.6 Species sex

First overall breakdown by female and male without including unreported or hermaphroditic animals

EIPAAB_database %>% 
  dplyr::group_by(unique_population_id) %>% 
  dplyr::sample_n(1) %>% # sampling one row per article per species (i.e. ignoring multiple rows per article for compounds)
  dplyr::ungroup() %>% 
  dplyr::group_by(species_sex) %>% 
  dplyr::reframe(n = n()) %>%
  dplyr::mutate(species_sex = str_trim(species_sex)) %>%
  tidyr::separate_rows(species_sex, sep = ";") %>% # each spp has multiple habitats the string needs splitting
  dplyr::group_by(species_sex) %>% 
  dplyr::summarise(n_articles = sum(n), .groups = 'drop') %>%  # now a sum for each habitat
  tidyr::complete(species_sex, 
                  fill = list(n_articles = 0)) %>%  # make a full df with empty categories = 0
  dplyr::ungroup() %>%
  dplyr::filter(species_sex == "Female" | species_sex == "Male") %>% 
  dplyr::mutate(total_sex = sum(n_articles)) %>% 
  dplyr::ungroup() %>% 
  dplyr::mutate(overall_percent = round(n_articles/total_sex*100,1))
## # A tibble: 2 × 4
##   species_sex n_articles total_sex overall_percent
##   <chr>            <int>     <int>           <dbl>
## 1 Female             280       623            44.9
## 2 Male               343       623            55.1

Let’s take a look at the sex of spp used in the EIPAAB database

sex_summary_all <- EIPAAB_database %>% 
  dplyr::group_by(unique_population_id) %>% 
  dplyr::sample_n(1) %>% # sampling one row per article per species (i.e. ignoring multiple rows per article for compounds)
  dplyr::ungroup() %>% 
  dplyr::group_by(study_motivation, species_sex) %>% 
  dplyr::reframe(n = n()) %>%
  dplyr::mutate(species_sex = str_trim(species_sex)) %>%
  tidyr::separate_rows(species_sex, sep = ";") %>% # each spp has multiple habitats the string needs splitting
  dplyr::group_by(species_sex, study_motivation) %>% 
  dplyr::summarise(n_articles = sum(n), .groups = 'drop') %>%  # now a sum for each habitat
  tidyr::complete(species_sex, study_motivation, 
                  fill = list(n_articles = 0)) %>%  # make a full df with empty categories = 0
  dplyr::ungroup() %>% 
  dplyr::group_by(study_motivation) %>% 
  dplyr::mutate(total_sex = sum(n_articles)) %>% 
  dplyr::ungroup() %>% 
  dplyr::mutate(overall_prop = n_articles/total_sex)
sex_summary_all
## # A tibble: 12 × 5
##    species_sex              study_motivation n_articles total_sex overall_prop
##    <chr>                    <fct>                 <int>     <int>        <dbl>
##  1 Female                   Environmental           136       645      0.211  
##  2 Female                   Medical                  91       322      0.283  
##  3 Female                   Basic research           53       206      0.257  
##  4 Hermaphrodites           Environmental             4       645      0.00620
##  5 Hermaphrodites           Medical                   0       322      0      
##  6 Hermaphrodites           Basic research            0       206      0      
##  7 Male                     Environmental           180       645      0.279  
##  8 Male                     Medical                  99       322      0.307  
##  9 Male                     Basic research           64       206      0.311  
## 10 Unknown or not specified Environmental           325       645      0.504  
## 11 Unknown or not specified Medical                 132       322      0.410  
## 12 Unknown or not specified Basic research           89       206      0.432

Let’s look at just the proportion of those defined as male and female

sex_male_female <- sex_summary_all %>%
    dplyr::filter(species_sex == "Female" | species_sex == "Male") %>%
    dplyr::select(-total_sex, -overall_prop) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_male_female = sum(n_articles)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(prop = n_articles/total_male_female)

Making the plot

sex_order <- c("Female", "Male")

color_theme <- c("#eb4729", "#1b909a")

# Calculate cumulative positions for text labels
sex_male_female <- sex_male_female %>%
    dplyr::mutate(species_sex = factor(species_sex, levels = sex_order)) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::arrange(desc(species_sex)) %>%
    dplyr::mutate(cumulative_prop = cumsum(prop) - prop/2)

# Create the plot
sex_fig <- sex_male_female %>%
    mutate(study_motivation = fct_relevel(study_motivation, "Basic research", "Medical",
        "Environmental")) %>%
    ggplot(aes(y = prop, x = study_motivation, fill = species_sex, group = species_sex)) +
    geom_bar(stat = "identity", width = 0.9) + geom_text(aes(label = round(prop,
    2), y = cumulative_prop), color = "white", size = 3) + scale_fill_manual(values = color_theme,
    name = "Sex") + theme_classic() + theme(legend.position = "right") + labs(x = "Study motivation",
    y = "Proportion of all species assigned to female or male") + coord_flip()

sex_fig

setwd(figures_path)
ggsave("spp_sex_fig.pdf", plot = sex_fig, width = 10, height = 5)

Now let’s look at those not assgined to a sex

sex_summary_info <- sex_summary_all %>%
    dplyr::mutate(sex_reported = if_else(species_sex == "Unknown or not specified",
        "No", "Yes")) %>%
    dplyr::group_by(sex_reported) %>%
    dplyr::reframe(n = sum(n_articles))

n_total <- sex_summary_info %>%
    dplyr::reframe(n_total = sum(n)) %>%
    dplyr::pull(n_total)

sex_summary_info <- sex_summary_info %>%
    dplyr::mutate(prop = n/n_total)

Here’s the plot

# Define the black and grey color theme
black_and_grey <- c("#BCBEC0", "#414042")

yes_order <- c("Yes", "No")

# Calculate cumulative positions for text labels
sex_summary_info <- sex_summary_info %>%
  dplyr::mutate(sex_reported = factor(sex_reported, levels = yes_order)) %>% 
  dplyr::arrange(desc(sex_reported)) %>% 
  dplyr::mutate(cumulative_prop = cumsum(prop) - prop / 2)

sex_info_fig <- sex_summary_info %>%
  dplyr::mutate(sex_reported = factor(sex_reported, levels = yes_order)) %>% 
  ggplot(aes(y = prop, x = 1, fill = sex_reported)) +
  geom_bar(stat = "identity", width = 0.9) +
  geom_text(aes(label = round(prop, 2), y = cumulative_prop), color = "white") + 
  scale_fill_manual(values = black_and_grey, name = "Sex reported") + 
  theme_classic() +
  theme(legend.position = "right",
        axis.text.x = element_blank(),  # Remove x-axis text
        axis.ticks.x = element_blank()  # Remove x-axis ticks 
        ) +
  labs(
    x = "",
    y = "Proportion of all species"
  )
sex_info_fig

setwd(figures_path)
ggsave("spp_sex_info_fig.pdf", plot = sex_info_fig, width = 2.5, height = 5)

12.7 Species source

Breakdown without unreported

EIPAAB_database %>% 
  dplyr::group_by(unique_population_id) %>% 
  dplyr::sample_n(1) %>% # sampling one row per article per species (i.e. ignoring multiple rows per article for compounds)
  dplyr::ungroup() %>% 
  dplyr::group_by(species_source) %>% 
  dplyr::reframe(n = n()) %>%
  dplyr::mutate(species_source = str_trim(species_source)) %>%
  tidyr::separate_rows(species_source, sep = ";") %>% # each spp has multiple habitats the string needs splitting
  dplyr::group_by(species_source) %>% 
  dplyr::summarise(n_articles = sum(n), .groups = 'drop') %>%  # now a sum for each habitat
  tidyr::complete(species_source, 
                  fill = list(n_articles = 0)) %>%  # make a full df with empty categories = 0
  dplyr::filter(species_source != "Not reported") %>% 
  dplyr::ungroup() %>% 
  dplyr::mutate(total_source = sum(n_articles)) %>% 
  dplyr::ungroup() %>% 
  dplyr::mutate(overall_percent = round(n_articles/total_source*100, 1)) %>% 
  dplyr::arrange(desc(overall_percent))
## # A tibble: 5 × 4
##   species_source                     n_articles total_source overall_percent
##   <chr>                                   <int>        <int>           <dbl>
## 1 Commercial supplier or fish farm          305          802            38  
## 2 Lab stock of undisclosed origin           213          802            26.6
## 3 Wild collected                            196          802            24.4
## 4 Lab stock from commercial supplier         55          802             6.9
## 5 Lab stock from wild population             33          802             4.1

Let’s look at where the animals were sourced for articles in the EIPAAB database

source_summary_all <- EIPAAB_database %>% 
  dplyr::group_by(unique_population_id) %>% 
  dplyr::sample_n(1) %>% # sampling one row per article per species (i.e. ignoring multiple rows per article for compounds)
  dplyr::ungroup() %>% 
  dplyr::group_by(study_motivation, species_source) %>% 
  dplyr::reframe(n = n()) %>%
  dplyr::mutate(species_source = str_trim(species_source)) %>%
  tidyr::separate_rows(species_source, sep = ";") %>% # each spp has multiple habitats the string needs splitting
  dplyr::group_by(species_source, study_motivation) %>% 
  dplyr::summarise(n_articles = sum(n), .groups = 'drop') %>%  # now a sum for each habitat
  tidyr::complete(species_source, study_motivation, 
                  fill = list(n_articles = 0)) %>%  # make a full df with empty categories = 0
  dplyr::ungroup() %>% 
  dplyr::group_by(study_motivation) %>% 
  dplyr::mutate(total_source = sum(n_articles)) %>% 
  dplyr::ungroup() %>% 
  dplyr::mutate(overall_prop = n_articles/total_source)
source_summary_all
## # A tibble: 18 × 5
##    species_source          study_motivation n_articles total_source overall_prop
##    <chr>                   <fct>                 <int>        <int>        <dbl>
##  1 Commercial supplier or… Environmental           134          548      0.245  
##  2 Commercial supplier or… Medical                 100          240      0.417  
##  3 Commercial supplier or… Basic research           71          162      0.438  
##  4 Lab stock from commerc… Environmental            29          548      0.0529 
##  5 Lab stock from commerc… Medical                  16          240      0.0667 
##  6 Lab stock from commerc… Basic research           10          162      0.0617 
##  7 Lab stock from wild po… Environmental            25          548      0.0456 
##  8 Lab stock from wild po… Medical                   1          240      0.00417
##  9 Lab stock from wild po… Basic research            7          162      0.0432 
## 10 Lab stock of undisclos… Environmental           119          548      0.217  
## 11 Lab stock of undisclos… Medical                  63          240      0.262  
## 12 Lab stock of undisclos… Basic research           31          162      0.191  
## 13 Not reported            Environmental            72          548      0.131  
## 14 Not reported            Medical                  51          240      0.212  
## 15 Not reported            Basic research           25          162      0.154  
## 16 Wild collected          Environmental           169          548      0.308  
## 17 Wild collected          Medical                   9          240      0.0375 
## 18 Wild collected          Basic research           18          162      0.111
source_summary <- source_summary_all %>%
    dplyr::filter(species_source != "Not reported") %>%
    dplyr::select(species_source, study_motivation, n_articles) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_reported = sum(n_articles)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(prop = n_articles/total_reported)
source_summary
## # A tibble: 15 × 5
##    species_source             study_motivation n_articles total_reported    prop
##    <chr>                      <fct>                 <int>          <int>   <dbl>
##  1 Commercial supplier or fi… Environmental           134            476 0.282  
##  2 Commercial supplier or fi… Medical                 100            189 0.529  
##  3 Commercial supplier or fi… Basic research           71            137 0.518  
##  4 Lab stock from commercial… Environmental            29            476 0.0609 
##  5 Lab stock from commercial… Medical                  16            189 0.0847 
##  6 Lab stock from commercial… Basic research           10            137 0.0730 
##  7 Lab stock from wild popul… Environmental            25            476 0.0525 
##  8 Lab stock from wild popul… Medical                   1            189 0.00529
##  9 Lab stock from wild popul… Basic research            7            137 0.0511 
## 10 Lab stock of undisclosed … Environmental           119            476 0.25   
## 11 Lab stock of undisclosed … Medical                  63            189 0.333  
## 12 Lab stock of undisclosed … Basic research           31            137 0.226  
## 13 Wild collected             Environmental           169            476 0.355  
## 14 Wild collected             Medical                   9            189 0.0476 
## 15 Wild collected             Basic research           18            137 0.131
source_order <- c("Wild collected", "Lab stock from wild population", "Lab stock of undisclosed origin",
    "Lab stock from commercial supplier", "Commercial supplier or fish farm")

# Define the black and grey color theme
color_theme <- c("#607C3B", "#A7D271", "#6B6E70", "#A66EAF", "#61346B")

# Calculate cumulative positions for text labels
source_summary <- source_summary %>%
    dplyr::mutate(species_source = factor(species_source, levels = source_order)) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::arrange(desc(species_source)) %>%
    dplyr::mutate(cumulative_prop = cumsum(prop) - prop/5)

# Create the plot
source_fig <- source_summary %>%
    mutate(study_motivation = fct_relevel(study_motivation, "Basic research", "Medical",
        "Environmental")) %>%
    ggplot(aes(y = prop, x = study_motivation, fill = species_source, group = species_source)) +
    geom_bar(stat = "identity", width = 0.9) + geom_text(aes(label = round(prop,
    2), y = cumulative_prop), color = "white", size = 3) + scale_fill_manual(values = color_theme,
    name = "Life stage") + theme_classic() + theme(legend.position = "right") + labs(x = "Study motivation",
    y = "Proportion of all species with a described source") + coord_flip()

source_fig

setwd(figures_path)
ggsave("spp_source_fig.pdf", plot = source_fig, width = 10, height = 5)

Now let’s look at those not assigned a source

source_summary_info <- source_summary_all %>%
    dplyr::mutate(source_reported = if_else(species_source == "Not reported", "No",
        "Yes")) %>%
    dplyr::group_by(source_reported) %>%
    dplyr::reframe(n = sum(n_articles))

n_total <- source_summary_info %>%
    dplyr::reframe(n_total = sum(n)) %>%
    dplyr::pull(n_total)

source_summary_info <- source_summary_info %>%
    dplyr::mutate(prop = n/n_total)

Here’s the plot

# Define the black and grey color theme
black_and_grey <- c("#BCBEC0", "#414042")

yes_order <- c("Yes", "No")

# Calculate cumulative positions for text labels
source_summary_info <- source_summary_info %>%
  dplyr::mutate(source_reported = factor(source_reported, levels = yes_order)) %>% 
  dplyr::arrange(desc(source_reported)) %>% 
  dplyr::mutate(cumulative_prop = cumsum(prop) - prop / 2)

source_info_fig <- source_summary_info %>%
  dplyr::mutate(source_reported = factor(source_reported, levels = yes_order)) %>% 
  ggplot(aes(y = prop, x = 1, fill = source_reported)) +
  geom_bar(stat = "identity", width = 0.9) +
  geom_text(aes(label = round(prop, 2), y = cumulative_prop), color = "white") + 
  scale_fill_manual(values = black_and_grey, name = "Source reported") + 
  theme_classic() +
  theme(legend.position = "right",
        axis.text.x = element_blank(),  # Remove x-axis text
        axis.ticks.x = element_blank()  # Remove x-axis ticks 
        ) +
  labs(
    x = "",
    y = "Proportion of all species"
  )
source_info_fig

setwd(figures_path)
ggsave("spp_source_info_fig.pdf", plot = source_info_fig, width = 5, height = 10)

13 Compounds

13.1 Number of compounds in database

There are 426 distinct compounds in the database

EIPAAB_database %>%
    dplyr::distinct(compound_name) %>%
    nrow()
## [1] 426

13.1.1 Number of compounds per study

article_n <- EIPAAB_database %>%
    dplyr::distinct(article_id) %>%
    nrow(.)

compound_n_summary <- EIPAAB_database %>%
    dplyr::group_by(article_id) %>%
    dplyr::sample_n(1) %>%
    dplyr::ungroup() %>%
    dplyr::group_by(compound_n) %>%
    dplyr::reframe(n = n(), percent = round((n/article_n) * 100, 1))

compound_n_summary
## # A tibble: 18 × 3
##    compound_n     n percent
##         <int> <int>   <dbl>
##  1          1   624    69.3
##  2          2   127    14.1
##  3          3    67     7.4
##  4          4    32     3.6
##  5          5    16     1.8
##  6          6     8     0.9
##  7          7     6     0.7
##  8          8     5     0.6
##  9          9     1     0.1
## 10         10     2     0.2
## 11         11     3     0.3
## 12         12     2     0.2
## 13         13     2     0.2
## 14         14     2     0.2
## 15         16     1     0.1
## 16         18     1     0.1
## 17         25     1     0.1
## 18         52     1     0.1

How mnay used more then 5

compound_n_summary %>%
    dplyr::filter(compound_n > 5) %>%
    reframe(n = sum(n), percent = round((n/article_n) * 100, 1))
## # A tibble: 1 × 2
##       n percent
##   <int>   <dbl>
## 1    35     3.9
compound_n_summary <- EIPAAB_database %>%
    dplyr::group_by(article_id) %>%
    dplyr::sample_n(1) %>%
    dplyr::ungroup() %>%
    dplyr::group_by(compound_n, study_motivation) %>%
    dplyr::summarise(n = n(), .groups = "drop") %>%
    tidyr::complete(compound_n, study_motivation, fill = list(n = 0)) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_motivation = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(prop_motivation = n/total_motivation)

compound_n_summary
## # A tibble: 54 × 5
##    compound_n study_motivation     n total_motivation prop_motivation
##         <int> <fct>            <int>            <int>           <dbl>
##  1          1 Environmental      389              510          0.763 
##  2          1 Medical            135              234          0.577 
##  3          1 Basic research     100              157          0.637 
##  4          2 Environmental       61              510          0.120 
##  5          2 Medical             42              234          0.179 
##  6          2 Basic research      24              157          0.153 
##  7          3 Environmental       27              510          0.0529
##  8          3 Medical             26              234          0.111 
##  9          3 Basic research      14              157          0.0892
## 10          4 Environmental       17              510          0.0333
## # ℹ 44 more rows
# Define the colour palette
motivation_colour_theme <- c("#60BD6C", "#D359A1", "#3C82C4") # Making colour theme to apply to plot

compound_n_oder <- c(1:9, ">10")

compound_n_fig <- compound_n_summary %>% 
  dplyr::mutate(
    compound_n = as.character(if_else(compound_n > 10, 10, compound_n)), # Grouping cases above 10
    compound_n = if_else(compound_n == "10", ">10", compound_n)
    ) %>% 
  dplyr::group_by(compound_n, study_motivation) %>% 
  dplyr::reframe(n = sum(n)) %>% 
  dplyr::mutate(compound_n = factor(compound_n, levels = compound_n_oder)) %>%
  ggplot(aes(x=compound_n, y=n, colour = study_motivation, fill = study_motivation, group = study_motivation)) +
  geom_col(position = position_dodge(width = 0.8), width = 0.1) +
  geom_point(position = position_dodge(width = 0.8), size = 3) +
  geom_text(aes(label = n), vjust=-0.6, size=3.5, color="black", position =  position_dodge(width = 0.8)) +
  scale_colour_manual(values = motivation_colour_theme, name = "Study motivation") +
  scale_fill_manual(values = motivation_colour_theme, name = "Study motivation") +
  theme_classic() +
   labs(
    x = "",
    y = "Number of studies"
  ) +
   theme()

compound_n_fig

setwd(figures_path)
ggsave("comp_compound_n_fig.pdf", plot = compound_n_fig, width = 10, height = 5)

13.2 Therputic diversity in the database

First lets see how many compounds have an ATC classification.

305 out of 426 (71.6%)

EIPAAB_database %>% 
  dplyr::group_by(compound_name) %>% 
  dplyr::sample_n(1) %>% # sampling one row per article per species (i.e. ignoring multiple rows per article for compounds)
  dplyr::ungroup() %>% 
  dplyr::group_by(compound_atc_boolean) %>% 
  dplyr::reframe(n = length(compound_atc_boolean))
## # A tibble: 2 × 2
##   compound_atc_boolean     n
##   <chr>                <int>
## 1 No                     121
## 2 Yes                    305

13.2.1 ATC level 1

Let’s seem how many classes there are at the Anatomical Therapeutic Chemical (ATC) level 1

There are 14 classes at the 1st ATC level (the highest class of the ATC). This is ever class at the first level

n_compound_atc <- EIPAAB_database %>% 
  dplyr::filter(compound_atc_boolean == "Yes") %>% 
  dplyr::distinct(compound_name) %>% 
  nrow(.)

compound_ATC_L1_summary <- EIPAAB_database %>% 
  dplyr::group_by(compound_name) %>% 
  dplyr::sample_n(1) %>% # sampling one row per article per species (i.e. ignoring multiple rows per article for compounds)
  dplyr::ungroup() %>% 
  dplyr::filter(compound_atc_boolean == "Yes") %>% 
  dplyr::group_by(compound_atc_level_1) %>% 
  dplyr::reframe(n = n()) %>%
  dplyr::mutate(compound_atc_level_1 = str_trim(compound_atc_level_1)) %>%
  tidyr::separate_rows(compound_atc_level_1, sep = ";") %>% # each spp has multiple habitats the string needs splitting
  dplyr::group_by(compound_atc_level_1) %>% 
  dplyr::reframe(n = sum(n),
                 percent = round(n/n_compound_atc*100,1),
                 measure = "compounds") %>% # now a sum for each habitat
  arrange(desc(n))

compound_ATC_L1_summary
## # A tibble: 14 × 4
##    compound_atc_level_1                                        n percent measure
##    <chr>                                                   <int>   <dbl> <chr>  
##  1 n nervous system                                          137    44.9 compou…
##  2 c cardiovascular system                                    49    16.1 compou…
##  3 a alimentary tract and metabolism                          35    11.5 compou…
##  4 s sensory organs                                           34    11.1 compou…
##  5 g genito urinary system and sex hormones                   30     9.8 compou…
##  6 j antiinfectives for systemic use                          28     9.2 compou…
##  7 d dermatologicals                                          27     8.9 compou…
##  8 r respiratory system                                       26     8.5 compou…
##  9 l antineoplastic and immunomodulating agents               19     6.2 compou…
## 10 m musculo-skeletal system                                  12     3.9 compou…
## 11 v various                                                   9     3   compou…
## 12 h systemic hormonal preparations, excl. sex hormones a…     8     2.6 compou…
## 13 p antiparasitic products, insecticides and repellents       6     2   compou…
## 14 b blood and blood forming organs                            4     1.3 compou…

Now we will make a similar data file to look at the overall use in the database at each ATC level 1

n_data_atc <- EIPAAB_database %>% 
  dplyr::filter(compound_atc_boolean == "Yes") %>% 
  nrow(.)

compound_ATC_L1_data_summary <- EIPAAB_database %>% 
  dplyr::filter(compound_atc_boolean == "Yes") %>% 
  dplyr::group_by(compound_atc_level_1) %>% 
  dplyr::reframe(n = n()) %>%
  dplyr::mutate(compound_atc_level_1 = str_trim(compound_atc_level_1)) %>%
  tidyr::separate_rows(compound_atc_level_1, sep = ";") %>% # each spp has multiple habitats the string needs splitting
  dplyr::group_by(compound_atc_level_1) %>% 
  dplyr::reframe(n = sum(n),
                 percent =round(n/n_data_atc*100,1),
                 measure = "data") %>% # now a sum for each habitat
  arrange(desc(percent))
compound_ATC_L1_data_summary
## # A tibble: 14 × 4
##    compound_atc_level_1                                        n percent measure
##    <chr>                                                   <int>   <dbl> <chr>  
##  1 n nervous system                                         1120    72.9 data   
##  2 g genito urinary system and sex hormones                  201    13.1 data   
##  3 c cardiovascular system                                   158    10.3 data   
##  4 d dermatologicals                                         130     8.5 data   
##  5 s sensory organs                                          102     6.6 data   
##  6 a alimentary tract and metabolism                          93     6.1 data   
##  7 l antineoplastic and immunomodulating agents               89     5.8 data   
##  8 r respiratory system                                       76     4.9 data   
##  9 m musculo-skeletal system                                  58     3.8 data   
## 10 j antiinfectives for systemic use                          57     3.7 data   
## 11 v various                                                  32     2.1 data   
## 12 h systemic hormonal preparations, excl. sex hormones a…    15     1   data   
## 13 b blood and blood forming organs                           12     0.8 data   
## 14 p antiparasitic products, insecticides and repellents       7     0.5 data
ATC_L1_summary <- compound_ATC_L1_summary %>%
    rbind(., compound_ATC_L1_data_summary) %>%
    dplyr::mutate(value = if_else(measure == "compounds", n, percent))

This plot shows the number of different compounds in each ATC classification as well as the total proportion of data it makes up

measure_colour_theme <- c("black", "grey")  # Making colour theme to apply to plot

# Making a list of act names in the order that we want them in the plot
level_1_order <- ATC_L1_summary %>%
    dplyr::filter(measure == "data") %>%
    dplyr::arrange(value) %>%
    dplyr::pull(compound_atc_level_1)

# Making the plot
atc_level_1_fig <- ATC_L1_summary %>%
    dplyr::mutate(compound_atc_level_1 = factor(compound_atc_level_1, levels = level_1_order)) %>%
    ggplot(aes(x = compound_atc_level_1, y = value, colour = measure, fill = measure,
        group = measure)) + geom_col(position = position_dodge(width = 0.8), width = 0.2,
    colour = NA) + geom_point(position = position_dodge(width = 0.8), size = 3) +
    geom_text(aes(label = value), hjust = -0.6, size = 3.5, color = "black", position = position_dodge(width = 0.8)) +
    scale_colour_manual(values = measure_colour_theme, name = "Value type") + scale_fill_manual(values = measure_colour_theme,
    name = "Value type") + coord_flip() + scale_y_continuous(name = "Number of distinct compounds",
    sec.axis = sec_axis(~., name = "Total proportion of the database")  # Adjust scaling if needed
) +
    theme_classic() + labs(x = "", y = "Number of distict species in the database") +
    theme()

atc_level_1_fig

setwd(figures_path)
ggsave("comp_atc_level_1_fig.pdf", plot = atc_level_1_fig, width = 10, height = 10)

13.2.2 ATC level 3

Let’s seem how many classes there are at the Anatomical Therapeutic Chemical (ATC) level 3

There are 131 distinct classes

n_compound_atc <- EIPAAB_database %>% 
  dplyr::filter(compound_atc_boolean == "Yes") %>% 
  dplyr::distinct(compound_name) %>% 
  nrow(.)

compound_ATC_L3_summary <- EIPAAB_database %>% 
  dplyr::group_by(compound_name) %>% 
  dplyr::sample_n(1) %>% # sampling one row per article per species (i.e. ignoring multiple rows per article for compounds)
  dplyr::ungroup() %>% 
  dplyr::filter(compound_atc_boolean == "Yes") %>% 
  dplyr::group_by(compound_atc_level_3) %>% 
  dplyr::reframe(n = n()) %>%
  dplyr::mutate(compound_atc_level_3 = str_trim(compound_atc_level_3)) %>%
  tidyr::separate_rows(compound_atc_level_3, sep = ";") %>% # each spp has multiple habitats the string needs splitting
  dplyr::group_by(compound_atc_level_3) %>% 
  dplyr::reframe(n = sum(n),
                 percent = round(n/n_compound_atc*100,1),
                 measure = "compounds") %>% # now a sum for each habitat
  arrange(desc(n))

compound_ATC_L3_summary
## # A tibble: 131 × 4
##    compound_atc_level_3                                        n percent measure
##    <chr>                                                   <int>   <dbl> <chr>  
##  1 n06a antidepressants                                       27     8.9 compou…
##  2 n03a antiepileptics                                        18     5.9 compou…
##  3 n05a antipsychotics                                        14     4.6 compou…
##  4 a01a stomatological preparations                           12     3.9 compou…
##  5 n05b anxiolytics                                           11     3.6 compou…
##  6 n05c hypnotics and sedatives                               11     3.6 compou…
##  7 n06b psychostimulants, agents used for adhd and nootro…    11     3.6 compou…
##  8 r06a antihistamines for systemic use                       11     3.6 compou…
##  9 c07a beta blocking agents                                   9     3   compou…
## 10 d04a antipruritics, incl. antihistamines, anesthetics,…     9     3   compou…
## # ℹ 121 more rows

Now we will make a similar data file to look at the overall use in the database at each ATC level 3

n_data_atc <- EIPAAB_database %>% 
  dplyr::filter(compound_atc_boolean == "Yes") %>% 
  nrow(.)

compound_ATC_L3_data_summary <- EIPAAB_database %>% 
  dplyr::filter(compound_atc_boolean == "Yes") %>% 
  dplyr::group_by(compound_atc_level_3) %>% 
  dplyr::reframe(n = n()) %>%
  dplyr::mutate(compound_atc_level_3 = str_trim(compound_atc_level_3)) %>%
  tidyr::separate_rows(compound_atc_level_3, sep = ";") %>% # each spp has multiple habitats the string needs splitting
  dplyr::group_by(compound_atc_level_3) %>% 
  dplyr::reframe(n = sum(n),
                 percent = round(n/n_data_atc*100,1),
                 measure = "data") %>% # now a sum for each habitat
  arrange(desc(percent))
compound_ATC_L3_data_summary
## # A tibble: 131 × 4
##    compound_atc_level_3                                        n percent measure
##    <chr>                                                   <int>   <dbl> <chr>  
##  1 n06a antidepressants                                      425    27.7 data   
##  2 n03a antiepileptics                                       164    10.7 data   
##  3 n05b anxiolytics                                          149     9.7 data   
##  4 g03c estrogens                                            121     7.9 data   
##  5 n06b psychostimulants, agents used for adhd and nootro…    84     5.5 data   
##  6 l02a hormones and related agents                           64     4.2 data   
##  7 d11a other dermatological preparations                     62     4   data   
##  8 n05a antipsychotics                                        60     3.9 data   
##  9 m01a antiinflammatory and antirheumatic products, non-…    50     3.3 data   
## 10 n02a opioids                                               51     3.3 data   
## # ℹ 121 more rows

Here we make a new column called value where we combined the count of distinct compounds and proportion of data

ATC_L3_summary <- compound_ATC_L3_summary %>%
    rbind(., compound_ATC_L3_data_summary) %>%
    dplyr::mutate(value = if_else(measure == "compounds", n, percent))

This plot shows the number of different compounds in each ATC classification as well as the total proportion of data it makes up. This is done for only the 15 most commonly used groups.

measure_colour_theme <- c("black", "grey") # Making colour theme to apply to plot

# Making a list of act names in the order that we want them in the plot 
level_3_order_top_15 <- ATC_L3_summary %>% 
  dplyr::filter(measure == "data") %>% 
  dplyr::arrange(desc(value)) %>% 
  dplyr::slice(1:15) %>% 
  dplyr::arrange(desc(value)) %>%
  dplyr::pull(compound_atc_level_3)

# Making the plot
atc_level_3_fig <- ATC_L3_summary %>% 
  dplyr::filter(compound_atc_level_3 %in% level_3_order_top_15) %>% 
  dplyr::mutate(compound_atc_level_3 = factor(compound_atc_level_3, levels = level_3_order_top_15)) %>% 
  ggplot(aes(x=compound_atc_level_3, y=value, fill = measure, colour = measure, 
             group = measure)) +
  geom_col(position = position_dodge(width = 1), width = 0.2, colour = NA,) +
  geom_point(position = position_dodge(width = 1), size = 3) +
  geom_text(aes(label = value), vjust=-0.6, size=3.5, position =  position_dodge(width = 1)) +
  scale_colour_manual(values = measure_colour_theme, name = "Value type",
                      labels = c("Compounds (n)", "Percentage of data")) +
  scale_fill_manual(values = measure_colour_theme, name = "Value type",
                      labels = c("Compounds (n)", "Percentage of data")) +
  scale_y_continuous(
    name = "Distinct compounds",
    limits = c(0, 30),                   # Set the range of y-axis
    breaks = c(0, 10, 20, 30),           # Set the labels at 0, 10, 20, 30
    sec.axis = sec_axis(~ . , name = "Percentage of database") # Adjust scaling if needed
  ) +
  theme_classic() +
   labs(
    x = "",
    y = ""
  ) +
   theme(
    axis.text.y = element_text(size = 8),          # Change y-axis labels size
    axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1, size = 8), # Change x-axis labels orientation
    legend.title = element_text(size = 12),         # Change legend title size if needed
    legend.text = element_text(size = 10)  
   )

atc_level_3_fig

setwd(figures_path)
ggsave("atc_level_3_fig.pdf", plot = atc_level_3_fig, width = 10, height = 5)

13.3 Most common compounds

Overall the most common compounds are Fluoxetine, Diazepam and 17-alpha-ethinylestradiol

n_row <- EIPAAB_database %>%
    nrow(.)

compound_use <- EIPAAB_database %>%
    dplyr::group_by(compound_name) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::mutate(prop = n/n_row) %>%
    arrange(desc(prop))

compound_use
## # A tibble: 426 × 3
##    compound_name                 n   prop
##    <chr>                     <int>  <dbl>
##  1 Fluoxetine                  201 0.116 
##  2 Diazepam                     67 0.0385
##  3 17-alpha-ethinylestradiol    63 0.0362
##  4 Caffeine                     45 0.0259
##  5 Venlafaxine                  43 0.0247
##  6 Citalopram                   42 0.0241
##  7 Sertraline                   39 0.0224
##  8 Carbamazepine                38 0.0218
##  9 Buspirone                    30 0.0172
## 10 Morphine                     27 0.0155
## # ℹ 416 more rows

Let’s see what the numbers are for each motivation, but let’s also maintain the overall numbers so we can add it to the figure

n_row <- EIPAAB_database %>%
    nrow(.)

compound_use_motivation <- EIPAAB_database %>%
    dplyr::group_by(study_motivation, compound_name) %>%
    dplyr::summarise(n = n(), .groups = "drop") %>%
    tidyr::complete(compound_name, study_motivation, fill = list(n = 0))  # Making sure we have a complete dataframe

compound_use_motivation <- compound_use %>%
    dplyr::select(-prop) %>%
    dplyr::mutate(study_motivation = "All") %>%
    rbind(., compound_use_motivation)

compound_use_motivation
## # A tibble: 1,704 × 3
##    compound_name                 n study_motivation
##    <chr>                     <int> <chr>           
##  1 Fluoxetine                  201 All             
##  2 Diazepam                     67 All             
##  3 17-alpha-ethinylestradiol    63 All             
##  4 Caffeine                     45 All             
##  5 Venlafaxine                  43 All             
##  6 Citalopram                   42 All             
##  7 Sertraline                   39 All             
##  8 Carbamazepine                38 All             
##  9 Buspirone                    30 All             
## 10 Morphine                     27 All             
## # ℹ 1,694 more rows

The top 10 based on each study motivation as well as the overall total

top_10_comp_all_fig <- compound_use_motivation %>%
    dplyr::filter(study_motivation == "All") %>%
    dplyr::arrange(desc(n)) %>%
    dplyr::slice(1:10) %>%
    dplyr::mutate(compound_name = fct_reorder(compound_name, n)) %>%
    ggplot(aes(x = compound_name, y = n)) + geom_col(width = 0.1, colour = NA, fill = "grey") +
    geom_point(size = 3, colour = "grey", fill = "grey") + geom_text(aes(label = n),
    hjust = -0.6, size = 3.5, color = "black") + coord_flip() + theme_classic() +
    labs(title = "All", x = "", y = "Total use in the database") + theme(plot.title = element_text(size = 11))


top_10_comp_env_fig <- compound_use_motivation %>%
    dplyr::filter(study_motivation == "Environmental") %>%
    dplyr::arrange(desc(n)) %>%
    dplyr::slice(1:10) %>%
    dplyr::mutate(compound_name = fct_reorder(compound_name, n)) %>%
    ggplot(aes(x = compound_name, y = n)) + geom_col(width = 0.1, colour = NA, fill = "#60BD6C") +
    geom_point(size = 3, colour = "#60BD6C", fill = "#60BD6C") + geom_text(aes(label = n),
    hjust = -0.6, size = 3.5, color = "black") + coord_flip() + theme_classic() +
    labs(title = "Environmental", x = "", y = "Total use in the database") + theme(plot.title = element_text(size = 11))


top_10_comp_med_fig <- compound_use_motivation %>%
    dplyr::filter(study_motivation == "Medical") %>%
    dplyr::arrange(desc(n)) %>%
    dplyr::slice(1:10) %>%
    dplyr::mutate(compound_name = fct_reorder(compound_name, n)) %>%
    ggplot(aes(x = compound_name, y = n)) + geom_col(width = 0.1, colour = NA, fill = "#D359A1") +
    geom_point(size = 3, colour = "#D359A1", fill = "#D359A1") + geom_text(aes(label = n),
    hjust = -0.6, size = 3.5, color = "black") + coord_flip() + theme_classic() +
    labs(title = "Medical", x = "", y = "Total use in the database") + theme(plot.title = element_text(size = 11))

top_10_comp_base_fig <- compound_use_motivation %>%
    dplyr::filter(study_motivation == "Basic research") %>%
    dplyr::arrange(desc(n)) %>%
    dplyr::slice(1:10) %>%
    dplyr::mutate(compound_name = fct_reorder(compound_name, n)) %>%
    ggplot(aes(x = compound_name, y = n)) + geom_col(width = 0.1, colour = NA, fill = "#3C82C4") +
    geom_point(size = 3, colour = "#3C82C4", fill = "#3C82C4") + geom_text(aes(label = n),
    hjust = -0.6, size = 3.5, color = "black") + coord_flip() + theme_classic() +
    labs(title = "Basic Research", x = "", y = "Total use in the database") + theme(plot.title = element_text(size = 11))

Here are the resulting figures

top_10_comp_all_fig

top_10_comp_env_fig

top_10_comp_med_fig

top_10_comp_base_fig

Saving as PDFs

setwd(figures_path)
ggsave("comp_top_10_comp_all_fig.pdf", plot = top_10_comp_all_fig, width = 5, height = 10)
ggsave("comp_top_10_comp_env_fig.pdf", plot = top_10_comp_env_fig, width = 5, height = 10)
ggsave("comp_top_10_comp_med_fig.pdf", plot = top_10_comp_med_fig, width = 5, height = 10)
ggsave("comp_top_10_comp_base_fig.pdf", plot = top_10_comp_base_fig, width = 5, height = 10)
compound_use_motivation %>%
    dplyr::filter(compound_name == "17-alpha-ethinylestradiol")
## # A tibble: 4 × 3
##   compound_name                 n study_motivation
##   <chr>                     <int> <chr>           
## 1 17-alpha-ethinylestradiol    63 All             
## 2 17-alpha-ethinylestradiol    61 Environmental   
## 3 17-alpha-ethinylestradiol     0 Medical         
## 4 17-alpha-ethinylestradiol     2 Basic research

13.4 Mixtures

It was recorded whether the animals were also exposed to compound mixtures

EIPAAB_database %>%
    dplyr::group_by(article_id) %>%
    dplyr::sample_n(1) %>%
    dplyr::ungroup() %>%
    dplyr::reframe(mixture_yes = sum(compond_mixture == "Yes", na.rm = TRUE), mixture_no = sum(compond_mixture ==
        "No", na.rm = TRUE), mixture_percent = (mixture_yes/mixture_no) * 100)
## # A tibble: 1 × 3
##   mixture_yes mixture_no mixture_percent
##         <int>      <int>           <dbl>
## 1         165        736            22.4

Medical articles have a much higher use of mixtures

EIPAAB_database %>%
    dplyr::group_by(article_id) %>%
    dplyr::sample_n(1) %>%
    dplyr::ungroup() %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::reframe(mixture_yes = sum(compond_mixture == "Yes", na.rm = TRUE), mixture_no = sum(compond_mixture ==
        "No", na.rm = TRUE), mixture_percent = round((mixture_yes/mixture_no) * 100,
        1))
## # A tibble: 3 × 4
##   study_motivation mixture_yes mixture_no mixture_percent
##   <fct>                  <int>      <int>           <dbl>
## 1 Environmental             57        453            12.6
## 2 Medical                   76        158            48.1
## 3 Basic research            32        125            25.6

13.6 Exposure route

Data on the method of exposure was also extracted

nrow <- EIPAAB_database %>%
    nrow(.)

EIPAAB_database %>%
    dplyr::group_by(compound_expose_route) %>%
    dplyr::reframe(n = n(), percent = round((n/nrow) * 100, 1))
## # A tibble: 3 × 3
##   compound_expose_route               n percent
##   <chr>                           <int>   <dbl>
## 1 Other exposure route              223    12.8
## 2 Waterborne only                  1501    86.3
## 3 Waterborne plus any other route    16     0.9

13.7 Exposure length

The database has both the minimum and maximum duration of exposure prior to behavioural measure (compound_min_duration_exposure and compound_max_duration_exposure). Here we will focus on the maximum duration

These are the different categories of exposure length

EIPAAB_database %>%
    dplyr::distinct(compound_max_duration_exposure)
##    compound_max_duration_exposure
## 1               Less than 6 hours
## 2                   1 to 3 months
## 3                     3 to 8 days
## 4                   22 to 29 days
## 5               Multigenerational
## 6                   6 to 24 hours
## 7                     1 to 3 days
## 8                    8 to 15 days
## 9                      Not stated
## 10                  15 to 22 days
## 11              Transgenerational
## 12                  3 to 6 months
## 13                       Lifetime

Some articles did not report the exposure duration at all, or in sufficient detail to extract.

In total this occurred in 108 cases

EIPAAB_database %>%
    dplyr::filter(compound_min_duration_exposure == "Not stated" | compound_max_duration_exposure ==
        "Not stated") %>%
    nrow(.)
## [1] 108
exposure_duration_order <- c("Less than 6 hours", "6 to 24 hours", "1 to 3 days",
    "3 to 8 days", "8 to 15 days", "15 to 22 days", "22 to 29 days", "1 to 3 months",
    "3 to 6 months", "Lifetime", "Transgenerational", "Multigenerational")

nrow <- EIPAAB_database %>%
    dplyr::filter(compound_max_duration_exposure != "Not stated") %>%
    nrow(.)

exposure_duration_summary <- EIPAAB_database %>%
    dplyr::filter(compound_max_duration_exposure != "Not stated") %>%
    dplyr::group_by(compound_max_duration_exposure) %>%
    dplyr::reframe(n = n(), percent = round((n/nrow) * 100, 1)) %>%
    dplyr::mutate(compound_max_duration_exposure = factor(compound_max_duration_exposure,
        levels = exposure_duration_order)) %>%
    dplyr::arrange(compound_max_duration_exposure) %>%
    dplyr::mutate(study_motivation = "All")

exposure_duration_summary
## # A tibble: 12 × 4
##    compound_max_duration_exposure     n percent study_motivation
##    <fct>                          <int>   <dbl> <chr>           
##  1 Less than 6 hours                679    41.3 All             
##  2 6 to 24 hours                    129     7.8 All             
##  3 1 to 3 days                      106     6.4 All             
##  4 3 to 8 days                      318    19.3 All             
##  5 8 to 15 days                     101     6.1 All             
##  6 15 to 22 days                    113     6.9 All             
##  7 22 to 29 days                     59     3.6 All             
##  8 1 to 3 months                     83     5   All             
##  9 3 to 6 months                     23     1.4 All             
## 10 Lifetime                           9     0.5 All             
## 11 Transgenerational                 15     0.9 All             
## 12 Multigenerational                  9     0.5 All
exposure_duration_order <- c("Less than 6 hours", "6 to 24 hours", "1 to 3 days",
    "3 to 8 days", "8 to 15 days", "15 to 22 days", "22 to 29 days", "1 to 3 months",
    "3 to 6 months", "Lifetime", "Transgenerational", "Multigenerational")


exposure_duration_motivation_summary <- EIPAAB_database %>%
    dplyr::filter(compound_max_duration_exposure != "Not stated") %>%
    dplyr::group_by(compound_max_duration_exposure, study_motivation) %>%
    dplyr::summarise(n = n(), .groups = "drop") %>%
    tidyr::complete(compound_max_duration_exposure, study_motivation, fill = list(n = 0)) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_motivation = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round((n/total_motivation) * 100, 1)) %>%
    dplyr::select(-total_motivation)

exp_duration_motivation_summary <- exposure_duration_motivation_summary %>%
    rbind(exposure_duration_summary) %>%
    dplyr::mutate(compound_max_duration_exposure = factor(compound_max_duration_exposure,
        levels = rev(exposure_duration_order))) %>%
    dplyr::arrange(desc(compound_max_duration_exposure))

exp_duration_motivation_summary
## # A tibble: 48 × 4
##    compound_max_duration_exposure study_motivation     n percent
##    <fct>                          <fct>            <int>   <dbl>
##  1 Less than 6 hours              Environmental      124    15  
##  2 Less than 6 hours              Medical            285    61.2
##  3 Less than 6 hours              Basic research     270    76.7
##  4 Less than 6 hours              All                679    41.3
##  5 6 to 24 hours                  Environmental       62     7.5
##  6 6 to 24 hours                  Medical             53    11.4
##  7 6 to 24 hours                  Basic research      14     4  
##  8 6 to 24 hours                  All                129     7.8
##  9 1 to 3 days                    Environmental       74     9  
## 10 1 to 3 days                    Medical             22     4.7
## # ℹ 38 more rows
exp_duration_all_fig <- exp_duration_motivation_summary %>%
    dplyr::filter(study_motivation == "All") %>%
    ggplot(aes(x = compound_max_duration_exposure, y = percent)) + geom_col(width = 0.1,
    colour = NA, fill = "grey") + geom_point(size = 3, colour = "grey", fill = "grey") +
    geom_text(aes(label = percent), vjust = -0.6, size = 3.5, color = "black") +
    theme_classic() + coord_flip() + labs(title = "All", x = "", y = "Total percentage") +
    theme(plot.title = element_text(size = 11))


exp_duration_env_fig <- exp_duration_motivation_summary %>%
    dplyr::filter(study_motivation == "Environmental") %>%
    ggplot(aes(x = compound_max_duration_exposure, y = percent)) + geom_col(width = 0.1,
    colour = NA, fill = "#60BD6C") + geom_point(size = 3, colour = "#60BD6C", fill = "#60BD6C") +
    geom_text(aes(label = percent), vjust = -0.6, size = 3.5, color = "black") +
    theme_classic() + coord_flip() + labs(title = "Environmental", x = "", y = "Total percentage") +
    theme(plot.title = element_text(size = 11))

exp_duration_med_fig <- exp_duration_motivation_summary %>%
    dplyr::filter(study_motivation == "Medical") %>%
    ggplot(aes(x = compound_max_duration_exposure, y = percent)) + geom_col(width = 0.1,
    colour = NA, fill = "#D359A1") + geom_point(size = 3, colour = "#D359A1", fill = "#D359A1") +
    geom_text(aes(label = percent), vjust = -0.6, size = 3.5, color = "black") +
    theme_classic() + coord_flip() + labs(title = "Medical", x = "", y = "Total percentage") +
    theme(plot.title = element_text(size = 11))


exp_duration_base_fig <- exp_duration_motivation_summary %>%
    dplyr::filter(study_motivation == "Basic research") %>%
    ggplot(aes(x = compound_max_duration_exposure, y = percent)) + geom_col(width = 0.1,
    colour = NA, fill = "#3C82C4") + geom_point(size = 3, colour = "#3C82C4", fill = "#3C82C4") +
    geom_text(aes(label = percent), vjust = -0.6, size = 3.5, color = "black") +
    theme_classic() + coord_flip() + labs(title = "Basic research", x = "", y = "Total percentage") +
    theme(plot.title = element_text(size = 11))
exp_duration_all_fig

exp_duration_env_fig

exp_duration_med_fig

exp_duration_base_fig

setwd(figures_path)
ggsave("comp_exp_duration_all_fig.pdf", plot = exp_duration_all_fig, width = 8.3/3,
    height = 11.7/3)
ggsave("comp_exp_duration_env_fig.pdf", plot = exp_duration_env_fig, width = 8.3/3,
    height = 11.7/3)
ggsave("comp_exp_duration_med_fig.pdf", plot = exp_duration_med_fig, width = 8.3/3,
    height = 11.7/3)
ggsave("comp_exp_duration_base_fig.pdf", plot = exp_duration_base_fig, width = 8.3/3,
    height = 11.7/3)

13.8 Number of doses

Here I will look at the number of doses used. This was meassured as the total treatments (i.e. inculding control), so if we want to know the number of doses for the compound we need to subtract 1. I have done this below.

n_doses_summary <- EIPAAB_database %>%
    dplyr::filter(!is.na(compound_treatment_levels)) %>%
    dplyr::mutate(n_doses = compound_treatment_levels - 1) %>%
    dplyr::group_by(n_doses) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::mutate(total = sum(n), percent = round((n/total) * 100, 1), study_motivation = "All")
n_doses_summary
## # A tibble: 14 × 5
##    n_doses     n total percent study_motivation
##      <dbl> <int> <int>   <dbl> <chr>           
##  1       1   450  1514    29.7 All             
##  2       2   203  1514    13.4 All             
##  3       3   377  1514    24.9 All             
##  4       4   172  1514    11.4 All             
##  5       5   163  1514    10.8 All             
##  6       6    46  1514     3   All             
##  7       7    50  1514     3.3 All             
##  8       8    14  1514     0.9 All             
##  9       9    11  1514     0.7 All             
## 10      10    10  1514     0.7 All             
## 11      11    10  1514     0.7 All             
## 12      12     5  1514     0.3 All             
## 13      13     2  1514     0.1 All             
## 14      17     1  1514     0.1 All

Let’s see how many use more then 5

n_doses_summary %>%
    dplyr::filter(n_doses > 5) %>%
    dplyr::summarise(over_5_percent = sum(percent))
## # A tibble: 1 × 1
##   over_5_percent
##            <dbl>
## 1            9.8

Looking by study motivation

n_doses_motivation_summary <- EIPAAB_database %>%
    dplyr::filter(!is.na(compound_treatment_levels)) %>%
    dplyr::mutate(n_doses = compound_treatment_levels - 1) %>%
    dplyr::group_by(n_doses, study_motivation) %>%
    dplyr::summarise(n = n(), .groups = "drop") %>%
    tidyr::complete(n_doses, study_motivation, fill = list(n = 0)) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round((n/total) * 100, 1))
n_doses_motivation_summary
## # A tibble: 42 × 5
##    n_doses study_motivation     n total percent
##      <dbl> <fct>            <int> <int>   <dbl>
##  1       1 Environmental      175   824    21.2
##  2       1 Medical            173   397    43.6
##  3       1 Basic research     102   293    34.8
##  4       2 Environmental      142   824    17.2
##  5       2 Medical             31   397     7.8
##  6       2 Basic research      30   293    10.2
##  7       3 Environmental      184   824    22.3
##  8       3 Medical             88   397    22.2
##  9       3 Basic research     105   293    35.8
## 10       4 Environmental      112   824    13.6
## # ℹ 32 more rows

Making a plot

dose_order <- c(1:12, ">12")

doses_fig <- n_doses_motivation_summary %>% 
  dplyr::mutate(n_doses = as.character(if_else(n_doses>13, 13, n_doses)),
                n_doses = if_else(n_doses == "13", ">12", n_doses),
                n_doses = factor(n_doses, levels = dose_order)
                )%>% 
  ggplot(aes(x=n_doses, y=percent, colour = study_motivation, 
             fill = study_motivation, group = study_motivation)) +
  geom_point(position = position_dodge(width = 0.8), size = 3) +
  geom_line(size = 1) +
  geom_text(aes(label = percent), vjust=-0.6, size=3.5, color="black") +
  scale_colour_manual(values = motivation_colour_theme, name = "Study motivation") +
  scale_fill_manual(values = motivation_colour_theme, name = "Study motivation") +
  theme_classic() +
  facet_wrap(~study_motivation) +
  theme(
    legend.position = c(0.8, 0.9), # Positioning the legend in the top-left corner within the plot
    legend.justification = c(0, 1) # Ensuring the legend box aligns properly at the top-left corner
    ) +
   labs(
    x = "",
    y = "Number of studies"
  ) +
   theme()

doses_fig

setwd(figures_path)
ggsave("comp_doses_fig.pdf", plot = doses_fig, width = 8.3, height = 11.7/3)

## 9.8 Concentrations

Here I will have a look at the min and max and range of doses used in the database. For the MS, I am including only studies that reported in a mass to water volume measure so we can compare standardised unites (ug/L). This was the most common reporting methods (62% of all data; 1090 total).

nrow <- EIPAAB_database %>%
    nrow()

EIPAAB_database %>%
    dplyr::group_by(compound_min_dose_unit_std) %>%
    dplyr::reframe(n = n(), prop = n/nrow) %>%
    dplyr::arrange(desc(n))
## # A tibble: 7 × 3
##   compound_min_dose_unit_std     n    prop
##   <chr>                      <int>   <dbl>
## 1 ug/L                        1076 0.618  
## 2 uM                           397 0.228  
## 3 <NA>                         229 0.132  
## 4 uM/L                          25 0.0144 
## 5 ppm                            9 0.00517
## 6 uL/L                           2 0.00115
## 7 ug/g                           2 0.00115

Summary of the minimum concentration used (where reported in mass to volume)

EIPAAB_database <- EIPAAB_database %>%
    dplyr::mutate(range = compound_max_dose_std - compound_min_dose_std)
EIPAAB_database %>%
    dplyr::filter(compound_min_dose_unit_std == "ug/L", compound_max_dose_unit_std ==
        "ug/L") %>%
    dplyr::mutate(range = compound_max_dose_std - compound_min_dose_std) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::reframe(median_min = median(compound_min_dose_std, na.rm = T), sd_min = sd(compound_min_dose_std,
        na.rm = T), min_min = min(compound_min_dose_std, na.rm = T), max_min = max(compound_min_dose_std,
        na.rm = T), median_max = median(compound_max_dose_std, na.rm = T), sd_max = sd(compound_max_dose_std,
        na.rm = T), min_max = min(compound_max_dose_std, na.rm = T), max_max = max(compound_max_dose_std,
        na.rm = T), median_range = median(range, na.rm = T), sd_range = sd(range,
        na.rm = T), min_range = min(range, na.rm = T), max_range = max(range, na.rm = T))
## # A tibble: 3 × 13
##   study_motivation median_min   sd_min min_min max_min median_max sd_max min_max
##   <fct>                 <dbl>    <dbl>   <dbl>   <dbl>      <dbl>  <dbl>   <dbl>
## 1 Environmental         0.995   25256. 3.13e-6  5   e5        100 1.41e5   0.001
## 2 Medical            1000       74501. 5   e-2  5.40e5       5000 2.07e5   0.05 
## 3 Basic research     3000     5301683. 1   e-2  6   e7      10000 5.30e6   0.01 
## # ℹ 5 more variables: max_max <dbl>, median_range <dbl>, sd_range <dbl>,
## #   min_range <dbl>, max_range <dbl>

A plot for minimum doses, its on the log axis because the distribution is highly skewed motivation_colour_theme

motivation_colour_theme <- c("#60BD6C", "#D359A1", "#3C82C4")

min_conc_fig <- EIPAAB_database %>%
    dplyr::filter(compound_min_dose_unit_std == "ug/L") %>%
    ggplot(aes(x = log(compound_min_dose_std), fill = study_motivation, colour = study_motivation)) +
    stat_slab(alpha = 0.6, linewidth = 1.5, colour = NA) + stat_pointinterval(point_interval = "median_qi",
    position = position_dodge(width = 0.4, preserve = "single"), .width = c(0.89,
        0.95)) + scale_fill_manual(values = motivation_colour_theme, name = "Study motivation",
    guide = "none") + scale_colour_manual(values = motivation_colour_theme, name = "Study motivation") +
    theme_classic() + labs(x = "Log10 minimum dose (ug/L)", y = "Density") + theme(legend.position = "bottom")

min_conc_fig

setwd(figures_path)
ggsave("comp_min_conc_fig.pdf", plot = min_conc_fig, width = 5, height = 6)

A summary table so we can see what the corresponding raw values are in the plot

min_conc_summary <- EIPAAB_database %>%
    dplyr::filter(compound_min_dose_unit_std == "ug/L") %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::summarise(median = median(log(compound_min_dose_std), na.rm = TRUE), lower_89 = quantile(log(compound_min_dose_std),
        probs = 0.11, na.rm = TRUE), upper_89 = quantile(log(compound_min_dose_std),
        probs = 0.89, na.rm = TRUE), lower_95 = quantile(log(compound_min_dose_std),
        probs = 0.05, na.rm = TRUE), upper_95 = quantile(log(compound_min_dose_std),
        probs = 0.95, na.rm = TRUE), .groups = "drop") %>%
    # Transform to a format suitable for ggplot annotation
pivot_longer(cols = -study_motivation, names_to = "stat", values_to = "value") %>%
    dplyr::mutate(vaule_raw = format(exp(value), scientific = FALSE))
min_conc_summary
## # A tibble: 15 × 4
##    study_motivation stat        value vaule_raw         
##    <fct>            <chr>       <dbl> <chr>             
##  1 Environmental    median   -0.00503 "     0.994987437"
##  2 Environmental    lower_89 -5.41    "     0.004456651"
##  3 Environmental    upper_89  5.54    "   254.538265740"
##  4 Environmental    lower_95 -6.91    "     0.001000000"
##  5 Environmental    upper_95  8.35    "  4240.690713691"
##  6 Medical          median    6.91    "  1000.000000000"
##  7 Medical          lower_89  3.10    "    22.211490447"
##  8 Medical          upper_89 10.3     " 30000.000000000"
##  9 Medical          lower_95  0       "     1.000000000"
## 10 Medical          upper_95 11.5     "100000.000000000"
## 11 Basic research   median    8.01    "  3000.000000000"
## 12 Basic research   lower_89 -0.920   "     0.398400829"
## 13 Basic research   upper_89 10.8     " 50802.311370061"
## 14 Basic research   lower_95 -2.30    "     0.100000000"
## 15 Basic research   upper_95 11.5     "100000.000000000"

A plot for maximum doses, its on the log axis because the distribution is highly skewed motivation_colour_theme

motivation_colour_theme <- c("#60BD6C", "#D359A1", "#3C82C4")

max_conc_fig <- EIPAAB_database %>%
    dplyr::filter(compound_min_dose_unit_std == "ug/L") %>%
    ggplot(aes(x = log(compound_max_dose_std), fill = study_motivation, colour = study_motivation)) +
    stat_slab(alpha = 0.6, linewidth = 1.5, colour = NA) + stat_pointinterval(point_interval = "median_qi",
    position = position_dodge(width = 0.4, preserve = "single"), .width = c(0.89,
        0.95)) + scale_fill_manual(values = motivation_colour_theme, name = "Study motivation",
    guide = "none") + scale_colour_manual(values = motivation_colour_theme, name = "Study motivation") +
    theme_classic() + labs(x = "Log10 maximum dose (ug/L)", y = "Density") + theme(legend.position = "bottom")

max_conc_fig

setwd(figures_path)
ggsave("comp_max_conc_fig.pdf", plot = max_conc_fig, width = 5, height = 6)

A summary table so we can see what the corresponding raw values are in the plot

max_conc_summary <- EIPAAB_database %>%
    dplyr::filter(compound_min_dose_unit_std == "ug/L") %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::summarise(median = median(log(compound_max_dose_std), na.rm = TRUE), lower_89 = quantile(log(compound_max_dose_std),
        probs = 0.11, na.rm = TRUE), upper_89 = quantile(log(compound_max_dose_std),
        probs = 0.89, na.rm = TRUE), lower_95 = quantile(log(compound_max_dose_std),
        probs = 0.05, na.rm = TRUE), upper_95 = quantile(log(compound_max_dose_std),
        probs = 0.95, na.rm = TRUE), .groups = "drop") %>%
    # Transform to a format suitable for ggplot annotation
pivot_longer(cols = -study_motivation, names_to = "stat", values_to = "value") %>%
    dplyr::mutate(vaule_raw = format(exp(value), scientific = FALSE))
max_conc_summary
## # A tibble: 15 × 4
##    study_motivation stat      value vaule_raw         
##    <fct>            <chr>     <dbl> <chr>             
##  1 Environmental    median    4.61  "   100.000000000"
##  2 Environmental    lower_89 -3.00  "     0.049652545"
##  3 Environmental    upper_89 10.1   " 23247.868374564"
##  4 Environmental    lower_95 -4.62  "     0.009873911"
##  5 Environmental    upper_95 11.5   "100000.000000000"
##  6 Medical          median    8.52  "  5000.000000000"
##  7 Medical          lower_89  4.42  "    82.775528294"
##  8 Medical          upper_89 11.5   "100000.000000000"
##  9 Medical          lower_95  2.98  "    19.686403036"
## 10 Medical          upper_95 12.9   "408740.139635277"
## 11 Basic research   median    9.21  " 10000.000000000"
## 12 Basic research   lower_89  0.895 "     2.446887175"
## 13 Basic research   upper_89 11.5   "100000.000000000"
## 14 Basic research   lower_95 -2.30  "     0.100000000"
## 15 Basic research   upper_95 12.6   "300000.000000000"

A plot for the range of doses, its on the log axis because the distribution is highly skewed. This includes only studies that had more then one dose and reported concentration in a mass to volume metric.

motivation_colour_theme <- c("#60BD6C", "#D359A1", "#3C82C4")

range_conc_fig <- EIPAAB_database %>%
    dplyr::filter(compound_min_dose_unit_std == "ug/L") %>%
    dplyr::filter(range > 0) %>%
    ggplot(aes(x = log(range), fill = study_motivation, colour = study_motivation)) +
    stat_slab(alpha = 0.6, linewidth = 1.5, colour = NA) + stat_pointinterval(point_interval = "median_qi",
    position = position_dodge(width = 0.4, preserve = "single"), .width = c(0.89,
        0.95)) + scale_fill_manual(values = motivation_colour_theme, name = "Study motivation",
    guide = "none") + scale_colour_manual(values = motivation_colour_theme, name = "Study motivation") +
    theme_classic() + labs(x = "Log10 range (ug/L)", y = "Density") + theme(legend.position = "bottom")

range_conc_fig

setwd(figures_path)
ggsave("comp_range_conc_fig.pdf", plot = range_conc_fig, width = 5, height = 6)

A summary table so we can see what the corresponding raw values are in the plot

range_conc_summary <- EIPAAB_database %>%
    dplyr::filter(compound_min_dose_unit_std == "ug/L", range > 0) %>%
    dplyr::group_by(study_motivation) %>%
    summarise(median = median(log(range), na.rm = TRUE), lower_89 = quantile(log(range),
        probs = 0.055, na.rm = TRUE), upper_89 = quantile(log(range), probs = 0.945,
        na.rm = TRUE), lower_95 = quantile(log(range), probs = 0.025, na.rm = TRUE),
        upper_95 = quantile(log(range), probs = 0.975, na.rm = TRUE)) %>%
    # Transform to a format suitable for ggplot annotation
pivot_longer(cols = -study_motivation, names_to = "stat", values_to = "value") %>%
    dplyr::mutate(vaule_raw = format(exp(value), scientific = FALSE))
range_conc_summary
## # A tibble: 15 × 4
##    study_motivation stat       value vaule_raw        
##    <fct>            <chr>      <dbl> <chr>            
##  1 Environmental    median    5.38   "   217.80000000"
##  2 Environmental    lower_89 -3.00   "     0.05000498"
##  3 Environmental    upper_89 11.5    " 99995.93990911"
##  4 Environmental    lower_95 -4.07   "     0.01704190"
##  5 Environmental    upper_95 13.1    "491792.33880353"
##  6 Medical          median    9.10   "  9000.00000000"
##  7 Medical          lower_89  4.33   "    75.72276785"
##  8 Medical          upper_89 13.2    "539495.65697997"
##  9 Medical          lower_95  3.42   "    30.45013206"
## 10 Medical          upper_95 13.6    "846549.05789480"
## 11 Basic research   median    9.85   " 19000.00000000"
## 12 Basic research   lower_89  0.0872 "     1.09108007"
## 13 Basic research   upper_89 12.5    "270000.00000000"
## 14 Basic research   lower_95 -0.0102 "     0.98987944"
## 15 Basic research   upper_95 12.6    "299042.91267704"
env_min_conc_fig <- EIPAAB_database %>%
    dplyr::filter(study_motivation == "Environmental") %>%
    dplyr::filter(compound_min_dose_unit_std == "ug/L") %>%
    ggplot(aes(x = log(compound_min_dose_std))) + stat_slab(aes(alpha = 0.8, linewidth = 1.5)) +
    stat_pointinterval(point_interval = "median_qi", position = position_dodge(width = 0.4,
        preserve = "single"), .width = c(0.89, 0.95)) + theme_classic() + theme(legend.position = "none")

env_min_conc_fig

A summary table so we can see what the corresponding raw values are in the plot

env_conc_summary <- EIPAAB_database %>%
    filter(study_motivation == "Environmental", compound_min_dose_unit_std == "ug/L") %>%
    summarise(median = median(log(compound_min_dose_std), na.rm = TRUE), lower_89 = quantile(log(compound_min_dose_std),
        probs = 0.055, na.rm = TRUE), upper_89 = quantile(log(compound_min_dose_std),
        probs = 0.945, na.rm = TRUE), lower_95 = quantile(log(compound_min_dose_std),
        probs = 0.025, na.rm = TRUE), upper_95 = quantile(log(compound_min_dose_std),
        probs = 0.975, na.rm = TRUE)) %>%
    # Transform to a format suitable for ggplot annotation
pivot_longer(cols = everything(), names_to = "stat", values_to = "value") %>%
    dplyr::mutate(vaule_raw = format(exp(value), scientific = FALSE))
env_conc_summary
## # A tibble: 5 × 3
##   stat        value vaule_raw         
##   <chr>       <dbl> <chr>             
## 1 median   -0.00503 "    0.9949874371"
## 2 lower_89 -6.91    "    0.0010000000"
## 3 upper_89  7.79    " 2425.8399279662"
## 4 lower_95 -7.49    "    0.0005588055"
## 5 upper_95  9.67    "15901.5600424659"

13.9 Exposure location

Where the exposure itself was conducted

EIPAAB_database %>%
    dplyr::group_by(compound_exposure_location) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::mutate(total = sum(n), perecent = round(n/total * 100, 1))
## # A tibble: 3 × 4
##   compound_exposure_location                                    n total perecent
##   <chr>                                                     <int> <int>    <dbl>
## 1 Indoor laboratory setting or assumed indoors               1730  1740     99.4
## 2 Outdoor natural setting                                       4  1740      0.2
## 3 Outdoor restricted setting (cannot interact with wild sp…     6  1740      0.3

14 Behaviour

14.1 Counts of catagoires

First I will make a new variable called beahv_catgory_n, which will look at how many of our 10 broad behavioural categories were measured in the article.

The 10 over-arching categories were: (1) movement and locomotion, (2) pre-mating and mating behaviour, (3) post-mating behaviour, (4) aggression, (5) sociality, (6) cognition and learning, (7) anxiety and boldness, (8) foraging and feeding, (9) antipredator behaviour, and (10) other behaviours not categorised

This will take the some of all the behaviour categories., so can range from 1 to 10 for a single behavioural category to all categories.

EIPAAB_database <- EIPAAB_database %>%
    dplyr::mutate(behav_category_n = rowSums(across(starts_with("behav_") & ends_with("_boolean"))))

The majority of evidence seems to be based on a single behavioural category

EIPAAB_database %>%
    dplyr::group_by(behav_category_n) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::mutate(percent = round(n/sum(n) * 100, 1))
## # A tibble: 6 × 3
##   behav_category_n     n percent
##              <dbl> <int>   <dbl>
## 1                1  1206    69.3
## 2                2   400    23  
## 3                3   115     6.6
## 4                4    16     0.9
## 5                5     2     0.1
## 6                7     1     0.1

Is this the same by study motivation

EIPAAB_database %>%
    dplyr::group_by(behav_category_n, study_motivation) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_motivation = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round(n/total_motivation * 100, 1))
## # A tibble: 14 × 5
##    behav_category_n study_motivation     n total_motivation percent
##               <dbl> <fct>            <int>            <int>   <dbl>
##  1                1 Environmental      593              858    69.1
##  2                1 Medical            379              519    73  
##  3                1 Basic research     234              363    64.5
##  4                2 Environmental      180              858    21  
##  5                2 Medical            110              519    21.2
##  6                2 Basic research     110              363    30.3
##  7                3 Environmental       75              858     8.7
##  8                3 Medical             25              519     4.8
##  9                3 Basic research      15              363     4.1
## 10                4 Environmental        8              858     0.9
## 11                4 Medical              4              519     0.8
## 12                4 Basic research       4              363     1.1
## 13                5 Environmental        2              858     0.2
## 14                7 Medical              1              519     0.2

Here I make a dataframe where I have pivoted the data to long formate based on each of the 10 behaviour categories. This dataframe can be used to ask more spefic questiosn about the relationship between species, compound, and behaviour.

But first let’s use it to see what behaviours are most common overall all, and within each study motivation.

binary_behav <- EIPAAB_database %>%
    dplyr::select((starts_with("behav_") & ends_with("_boolean"))) %>%
    colnames()

PICO_long <- EIPAAB_database %>%
    tidyr::pivot_longer(., cols = all_of(binary_behav), names_to = "behav_category",
        values_to = "value") %>%
    dplyr::select(article_id, study_motivation, species_name, species_class, compound_name,
        compound_atc_level_3, behav_category, value) %>%
    dplyr::mutate(behav_category = behav_category %>%
        str_remove("behav_") %>%
        str_remove("_boolean"))
PICO_long
## # A tibble: 17,400 × 8
##    article_id study_motivation species_name species_class  compound_name
##    <chr>      <fct>            <chr>        <chr>          <chr>        
##  1 236660465  Environmental    Danio rerio  Actinopterygii Buspirone    
##  2 236660465  Environmental    Danio rerio  Actinopterygii Buspirone    
##  3 236660465  Environmental    Danio rerio  Actinopterygii Buspirone    
##  4 236660465  Environmental    Danio rerio  Actinopterygii Buspirone    
##  5 236660465  Environmental    Danio rerio  Actinopterygii Buspirone    
##  6 236660465  Environmental    Danio rerio  Actinopterygii Buspirone    
##  7 236660465  Environmental    Danio rerio  Actinopterygii Buspirone    
##  8 236660465  Environmental    Danio rerio  Actinopterygii Buspirone    
##  9 236660465  Environmental    Danio rerio  Actinopterygii Buspirone    
## 10 236660465  Environmental    Danio rerio  Actinopterygii Buspirone    
## # ℹ 17,390 more rows
## # ℹ 3 more variables: compound_atc_level_3 <chr>, behav_category <chr>,
## #   value <int>
behav_overall <- PICO_long %>%
    dplyr::group_by(behav_category) %>%
    reframe(n = sum(value)) %>%
    dplyr::mutate(percent = round(n/sum(n) * 100, 1)) %>%
    dplyr::arrange(desc(n))
behav_overall
## # A tibble: 10 × 3
##    behav_category     n percent
##    <chr>          <int>   <dbl>
##  1 movement         983    40.4
##  2 boldness         568    23.4
##  3 foraging         190     7.8
##  4 agression        145     6  
##  5 sociality        143     5.9
##  6 mating           122     5  
##  7 noncat            96     3.9
##  8 cognition         90     3.7
##  9 antipredator      85     3.5
## 10 post_mating       10     0.4
behav_motivation <- PICO_long %>%
    dplyr::group_by(behav_category, study_motivation) %>%
    dplyr::summarise(n = sum(value), .groups = "drop") %>%
    tidyr::complete(behav_category, study_motivation, fill = list(n = 0)) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_motivation = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round(n/total_motivation * 100, 1)) %>%
    dplyr::select(-total_motivation) %>%
    dplyr::arrange(desc(study_motivation))

behav_overall <- behav_motivation %>%
    dplyr::group_by(behav_category) %>%
    dplyr::reframe(n = sum(n)) %>%
    dplyr::mutate(percent = round(n/sum(n) * 100, 1), study_motivation = "Overall")

behav_motivation <- rbind(behav_overall, behav_motivation)
behav_motivation
## # A tibble: 40 × 4
##    behav_category     n percent study_motivation
##    <chr>          <int>   <dbl> <chr>           
##  1 agression        145     6   Overall         
##  2 antipredator      85     3.5 Overall         
##  3 boldness         568    23.4 Overall         
##  4 cognition         90     3.7 Overall         
##  5 foraging         190     7.8 Overall         
##  6 mating           122     5   Overall         
##  7 movement         983    40.4 Overall         
##  8 noncat            96     3.9 Overall         
##  9 post_mating       10     0.4 Overall         
## 10 sociality        143     5.9 Overall         
## # ℹ 30 more rows
motivation_colour_theme <- c("grey", "#60BD6C", "#D359A1", "#3C82C4")
behav_order <- c("movement", "boldness", "foraging", "antipredator", "mating", "post_mating",
    "agression", "sociality", "cognition", "noncat")
study_motivation_order <- c("Overall", "Environmental", "Medical", "Basic research")


behav_motivation_fig <- behav_motivation %>%
    dplyr::mutate(behav_category = factor(behav_category, levels = rev(behav_order)),
        study_motivation = factor(study_motivation, levels = study_motivation_order)) %>%
    ggplot(aes(x = behav_category, y = percent, colour = study_motivation, fill = study_motivation),
        group = study_motivation) + geom_col(width = 0.1, colour = NA) + geom_point(size = 3) +
    geom_text(aes(label = percent), vjust = -0.3, size = 3.5, color = "black") +
    theme_classic() + facet_grid(cols = vars(study_motivation)) + scale_colour_manual(values = motivation_colour_theme,
    name = "Study motivation") + scale_fill_manual(values = motivation_colour_theme,
    name = "Study motivation") + coord_flip() + labs(x = "", y = "Percentage") +
    theme(plot.title = element_text(size = 11))

behav_motivation_fig

setwd(figures_path)
ggsave("behav_motivation_fig.pdf", plot = behav_motivation_fig, width = 10, height = 5)

14.2 Behaviour sub-categories

behav_select <- EIPAAB_database %>%
    dplyr::select((starts_with("behav_") & !ends_with("_boolean") & !ends_with("is_social_context") &
        !ends_with("test_location") & !ends_with("category_n"))) %>%
    colnames()


behav_sub_cat_long <- EIPAAB_database %>%
    tidyr::pivot_longer(., cols = all_of(behav_select), names_to = "parent_category",
        values_to = "sub_category") %>%
    dplyr::select(article_id, study_motivation, species_name, species_class, compound_name,
        compound_atc_level_3, parent_category, sub_category) %>%
    dplyr::mutate(parent_category = parent_category %>%
        str_remove("behav_")) %>%
    tidyr::separate_rows(sub_category, sep = ";") %>%
    dplyr::filter(!is.na(sub_category))
behav_sub_cat_summary <- behav_sub_cat_long %>%
    dplyr::group_by(study_motivation, parent_category, sub_category) %>%
    dplyr::summarise(n_sub_cat = n(), .groups = "drop") %>%
    dplyr::group_by(study_motivation, parent_category) %>%
    dplyr::mutate(n_parent = sum(n_sub_cat)) %>%
    dplyr::ungroup() %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(n_motivation = sum(n_sub_cat)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent_sub_cat = n_sub_cat/n_parent, percent_parent = n_parent/n_motivation)
behav_sub_cat_summary
## # A tibble: 155 × 8
##    study_motivation parent_category sub_category n_sub_cat n_parent n_motivation
##    <fct>            <chr>           <chr>            <int>    <int>        <int>
##  1 Environmental    agression       aggression …        27       70         1511
##  2 Environmental    agression       aggression …        10       70         1511
##  3 Environmental    agression       aggression …        20       70         1511
##  4 Environmental    agression       aggression …         7       70         1511
##  5 Environmental    agression       locomotor a…         6       70         1511
##  6 Environmental    antipredator    locomotor a…        22      100         1511
##  7 Environmental    antipredator    response to…        10      100         1511
##  8 Environmental    antipredator    response to…         6      100         1511
##  9 Environmental    antipredator    response to…        20      100         1511
## 10 Environmental    antipredator    response to…        42      100         1511
## # ℹ 145 more rows
## # ℹ 2 more variables: percent_sub_cat <dbl>, percent_parent <dbl>
ring_plot_subcat <- behav_sub_cat_summary %>%
    dplyr::group_by(study_motivation, parent_category) %>%
    dplyr::mutate(ymax = cumsum(percent_sub_cat), ymin = lag(ymax, 1), ymin = if_else(is.na(ymin),
        0, ymin), labelPosition = (ymax + ymin)/2, label = paste0(sub_category, "\n (n = ",
        n_sub_cat, ")")) %>%
    dplyr::ungroup()

14.2.1 Movement plots

First making a complete dataset (adding zeros for missing sub-categories. in each motivation), and ordering by overall prevalence of sub-categories.

sub_category_order <- behav_sub_cat_summary %>%
    dplyr::filter(parent_category == "movement") %>%
    dplyr::group_by(sub_category) %>%
    dplyr::reframe(n = sum(n_sub_cat)) %>%
    dplyr::arrange(n) %>%
    dplyr::pull(sub_category)

movement_subcat <- behav_sub_cat_summary %>%
    dplyr::filter(parent_category == "movement") %>%
    dplyr::select(study_motivation, sub_category, percent_sub_cat, n_sub_cat, percent_parent) %>%
    tidyr::complete(sub_category, study_motivation, fill = list(percent_sub_cat = 0,
        n_sub_cat = 0)) %>%
    dplyr::mutate(sub_category = factor(sub_category, levels = sub_category_order))
beh_movement_subcat_fig <- movement_subcat %>%
    dplyr::mutate(percent_sub_cat = round(percent_sub_cat, 3) * 100) %>%
    ggplot(aes(x = sub_category, y = percent_sub_cat, colour = study_motivation,
        fill = study_motivation, group = study_motivation)) + geom_col(position = position_dodge(width = 0.8),
    width = 0.1) + geom_point(position = position_dodge(width = 0.8), size = 3) +
    geom_text(aes(label = percent_sub_cat), hjust = -0.6, size = 3.5, color = "black",
        position = position_dodge(width = 0.8)) + scale_colour_manual(values = motivation_colour_theme,
    name = "Study motivation") + scale_fill_manual(values = motivation_colour_theme,
    name = "Study motivation") + theme_classic() + coord_flip() + labs(x = "", y = "Percentage of data") +
    theme(legend.position = "none")

beh_movement_subcat_fig

n_subcat <- movement_subcat %>%
    dplyr::distinct(sub_category) %>%
    nrow(.)/10

setwd(figures_path)
ggsave("beh_movement_subcat_fig.pdf", plot = beh_movement_subcat_fig, width = 10,
    height = 11.7 * n_subcat)

If you would like to make a doughnut chart here’s the code. However, for categories that have 5 or more sub-categories like movement I don’t think this is the clearest way to present the data.

movement_subcat %>%
    dplyr::arrange(sub_category) %>%
    dplyr::arrange(study_motivation) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(ymax = cumsum(percent_sub_cat), ymin = lag(ymax, 1), ymin = if_else(is.na(ymin),
        0, ymin), labelPosition = (ymax + ymin)/2, label = if_else(n_sub_cat == 0,
        NA, n_sub_cat)) %>%
    dplyr::ungroup() %>%
    ggplot(aes(ymax = ymax, ymin = ymin, xmax = 4, xmin = 3, fill = sub_category)) +
    geom_rect() + coord_polar(theta = "y") + geom_label(x = 4, aes(y = labelPosition,
    label = label), size = 3, alpha = 0.8) + facet_wrap(~study_motivation) + xlim(c(2,
    5)) + theme_void() + theme(legend.position = "bottom")

14.2.2 Boldness plots

sub_category_order <- behav_sub_cat_summary %>%
    dplyr::filter(parent_category == "boldness") %>%
    dplyr::group_by(sub_category) %>%
    dplyr::reframe(n = sum(n_sub_cat)) %>%
    dplyr::arrange(n) %>%
    dplyr::pull(sub_category)

boldness_subcat <- behav_sub_cat_summary %>%
    dplyr::filter(parent_category == "boldness") %>%
    dplyr::select(study_motivation, sub_category, percent_sub_cat, n_sub_cat, percent_parent) %>%
    tidyr::complete(sub_category, study_motivation, fill = list(percent_sub_cat = 0,
        n_sub_cat = 0)) %>%
    dplyr::mutate(sub_category = factor(sub_category, levels = sub_category_order))
beh_boldness_subcat_fig <- boldness_subcat %>%
    dplyr::mutate(percent_sub_cat = round(percent_sub_cat, 3) * 100) %>%
    ggplot(aes(x = sub_category, y = percent_sub_cat, colour = study_motivation,
        fill = study_motivation, group = study_motivation)) + geom_col(position = position_dodge(width = 0.8),
    width = 0.1) + geom_point(position = position_dodge(width = 0.8), size = 3) +
    geom_text(aes(label = percent_sub_cat), hjust = -0.6, size = 3.5, color = "black",
        position = position_dodge(width = 0.8)) + scale_colour_manual(values = motivation_colour_theme,
    name = "Study motivation") + scale_fill_manual(values = motivation_colour_theme,
    name = "Study motivation") + theme_classic() + coord_flip() + labs(x = "", y = "Percentage of data") +
    theme(legend.position = "none")

beh_boldness_subcat_fig

n_subcat <- boldness_subcat %>%
    dplyr::distinct(sub_category) %>%
    nrow(.)/10

setwd(figures_path)
ggsave("beh_boldness_subcat_fig.pdf", plot = beh_boldness_subcat_fig, width = 10,
    height = 11.7 * n_subcat)

14.2.3 Foraging plots

sub_category_order <- behav_sub_cat_summary %>%
    dplyr::filter(parent_category == "foraging") %>%
    dplyr::group_by(sub_category) %>%
    dplyr::reframe(n = sum(n_sub_cat)) %>%
    dplyr::arrange(n) %>%
    dplyr::pull(sub_category)

foraging_subcat <- behav_sub_cat_summary %>%
    dplyr::filter(parent_category == "foraging") %>%
    dplyr::select(study_motivation, sub_category, percent_sub_cat, n_sub_cat, percent_parent) %>%
    tidyr::complete(sub_category, study_motivation, fill = list(percent_sub_cat = 0,
        n_sub_cat = 0)) %>%
    dplyr::mutate(sub_category = factor(sub_category, levels = sub_category_order))
beh_foraging_subcat_fig <- foraging_subcat %>%
    dplyr::mutate(percent_sub_cat = round(percent_sub_cat, 3) * 100) %>%
    ggplot(aes(x = sub_category, y = percent_sub_cat, colour = study_motivation,
        fill = study_motivation, group = study_motivation)) + geom_col(position = position_dodge(width = 0.8),
    width = 0.1) + geom_point(position = position_dodge(width = 0.8), size = 3) +
    geom_text(aes(label = percent_sub_cat), hjust = -0.6, size = 3.5, color = "black",
        position = position_dodge(width = 0.8)) + scale_colour_manual(values = motivation_colour_theme,
    name = "Study motivation") + scale_fill_manual(values = motivation_colour_theme,
    name = "Study motivation") + theme_classic() + coord_flip() + labs(x = "", y = "Percentage of data") +
    theme(legend.position = "none")

beh_foraging_subcat_fig

n_subcat <- foraging_subcat %>%
    dplyr::distinct(sub_category) %>%
    nrow(.)/10

setwd(figures_path)
ggsave("beh_foraging_subcat_fig.pdf", plot = beh_foraging_subcat_fig, width = 10,
    height = 11.7 * n_subcat)

14.2.4 Antipredator plots

sub_category_order <- behav_sub_cat_summary %>%
    dplyr::filter(parent_category == "antipredator") %>%
    dplyr::group_by(sub_category) %>%
    dplyr::reframe(n = sum(n_sub_cat)) %>%
    dplyr::arrange(n) %>%
    dplyr::pull(sub_category)

antipredator_subcat <- behav_sub_cat_summary %>%
    dplyr::filter(parent_category == "antipredator") %>%
    dplyr::select(study_motivation, sub_category, percent_sub_cat, n_sub_cat, percent_parent) %>%
    tidyr::complete(sub_category, study_motivation, fill = list(percent_sub_cat = 0,
        n_sub_cat = 0)) %>%
    dplyr::mutate(sub_category = factor(sub_category, levels = sub_category_order))
beh_antipredator_subcat_fig <- antipredator_subcat %>%
    dplyr::mutate(percent_sub_cat = round(percent_sub_cat, 3) * 100) %>%
    ggplot(aes(x = sub_category, y = percent_sub_cat, colour = study_motivation,
        fill = study_motivation, group = study_motivation)) + geom_col(position = position_dodge(width = 0.8),
    width = 0.1) + geom_point(position = position_dodge(width = 0.8), size = 3) +
    geom_text(aes(label = percent_sub_cat), hjust = -0.6, size = 3.5, color = "black",
        position = position_dodge(width = 0.8)) + scale_colour_manual(values = motivation_colour_theme,
    name = "Study motivation") + scale_fill_manual(values = motivation_colour_theme,
    name = "Study motivation") + theme_classic() + coord_flip() + labs(x = "", y = "Percentage of data") +
    theme(legend.position = "none")

beh_antipredator_subcat_fig

n_subcat <- antipredator_subcat %>%
    dplyr::distinct(sub_category) %>%
    nrow(.)/10

setwd(figures_path)
ggsave("beh_antipredator_subcat_fig.pdf", plot = beh_antipredator_subcat_fig, width = 10,
    height = 11.7 * n_subcat)

14.2.5 Mating plots

sub_category_order <- behav_sub_cat_summary %>%
    dplyr::filter(parent_category == "mating") %>%
    dplyr::group_by(sub_category) %>%
    dplyr::reframe(n = sum(n_sub_cat)) %>%
    dplyr::arrange(n) %>%
    dplyr::pull(sub_category)

mating_subcat <- behav_sub_cat_summary %>%
    dplyr::filter(parent_category == "mating") %>%
    dplyr::select(study_motivation, sub_category, percent_sub_cat, n_sub_cat, percent_parent) %>%
    tidyr::complete(sub_category, study_motivation, fill = list(percent_sub_cat = 0,
        n_sub_cat = 0)) %>%
    dplyr::mutate(sub_category = factor(sub_category, levels = sub_category_order))
beh_mating_subcat_fig <- mating_subcat %>%
    dplyr::mutate(percent_sub_cat = round(percent_sub_cat, 3) * 100) %>%
    ggplot(aes(x = sub_category, y = percent_sub_cat, colour = study_motivation,
        fill = study_motivation, group = study_motivation)) + geom_col(position = position_dodge(width = 0.8),
    width = 0.1) + geom_point(position = position_dodge(width = 0.8), size = 3) +
    geom_text(aes(label = percent_sub_cat), hjust = -0.6, size = 3.5, color = "black",
        position = position_dodge(width = 0.8)) + scale_colour_manual(values = motivation_colour_theme,
    name = "Study motivation") + scale_fill_manual(values = motivation_colour_theme,
    name = "Study motivation") + theme_classic() + coord_flip() + labs(x = "", y = "Percentage of data") +
    theme(legend.position = "none")

beh_mating_subcat_fig

n_subcat <- mating_subcat %>%
    dplyr::distinct(sub_category) %>%
    nrow(.)/10

setwd(figures_path)
ggsave("beh_mating_subcat_fig.pdf", plot = beh_mating_subcat_fig, width = 10, height = 11.7 *
    n_subcat)

14.2.6 Post mating plots

sub_category_order <- behav_sub_cat_summary %>%
    dplyr::filter(parent_category == "post_mating") %>%
    dplyr::group_by(sub_category) %>%
    dplyr::reframe(n = sum(n_sub_cat)) %>%
    dplyr::arrange(n) %>%
    dplyr::pull(sub_category)

post_mating_subcat <- behav_sub_cat_summary %>%
    dplyr::filter(parent_category == "post_mating") %>%
    dplyr::select(study_motivation, sub_category, percent_sub_cat, n_sub_cat, percent_parent) %>%
    tidyr::complete(sub_category, study_motivation, fill = list(percent_sub_cat = 0,
        n_sub_cat = 0)) %>%
    dplyr::mutate(sub_category = factor(sub_category, levels = sub_category_order))
beh_post_mating_subcat_fig <- post_mating_subcat %>%
    dplyr::mutate(percent_sub_cat = round(percent_sub_cat, 3) * 100) %>%
    ggplot(aes(x = sub_category, y = percent_sub_cat, colour = study_motivation,
        fill = study_motivation, group = study_motivation)) + geom_col(position = position_dodge(width = 0.8),
    width = 0.1) + geom_point(position = position_dodge(width = 0.8), size = 3) +
    geom_text(aes(label = percent_sub_cat), hjust = -0.6, size = 3.5, color = "black",
        position = position_dodge(width = 0.8)) + scale_colour_manual(values = motivation_colour_theme,
    name = "Study motivation") + scale_fill_manual(values = motivation_colour_theme,
    name = "Study motivation") + theme_classic() + coord_flip() + labs(x = "", y = "Percentage of data") +
    theme(legend.position = "none")

beh_post_mating_subcat_fig

n_subcat <- post_mating_subcat %>%
    dplyr::distinct(sub_category) %>%
    nrow(.)/10

setwd(figures_path)
ggsave("beh_post_mating_subcat_fig.pdf", plot = beh_post_mating_subcat_fig, width = 10,
    height = 11.7 * n_subcat)

14.2.7 Agression plots

sub_category_order <- behav_sub_cat_summary %>%
    dplyr::filter(parent_category == "agression") %>%
    dplyr::group_by(sub_category) %>%
    dplyr::reframe(n = sum(n_sub_cat)) %>%
    dplyr::arrange(n) %>%
    dplyr::pull(sub_category)

agression_subcat <- behav_sub_cat_summary %>%
    dplyr::filter(parent_category == "agression") %>%
    dplyr::select(study_motivation, sub_category, percent_sub_cat, n_sub_cat, percent_parent) %>%
    tidyr::complete(sub_category, study_motivation, fill = list(percent_sub_cat = 0,
        n_sub_cat = 0)) %>%
    dplyr::mutate(sub_category = factor(sub_category, levels = sub_category_order))
beh_agression_subcat_fig <- agression_subcat %>%
    dplyr::mutate(percent_sub_cat = round(percent_sub_cat, 3) * 100) %>%
    ggplot(aes(x = sub_category, y = percent_sub_cat, colour = study_motivation,
        fill = study_motivation, group = study_motivation)) + geom_col(position = position_dodge(width = 0.8),
    width = 0.1) + geom_point(position = position_dodge(width = 0.8), size = 3) +
    geom_text(aes(label = percent_sub_cat), hjust = -0.6, size = 3.5, color = "black",
        position = position_dodge(width = 0.8)) + scale_colour_manual(values = motivation_colour_theme,
    name = "Study motivation") + scale_fill_manual(values = motivation_colour_theme,
    name = "Study motivation") + theme_classic() + coord_flip() + labs(x = "", y = "Percentage of data") +
    theme(legend.position = "none")

beh_agression_subcat_fig

n_subcat <- agression_subcat %>%
    dplyr::distinct(sub_category) %>%
    nrow(.)/10

setwd(figures_path)
ggsave("beh_agression_subcat_fig.pdf", plot = beh_agression_subcat_fig, width = 10,
    height = 11.7 * n_subcat)

14.2.8 Sociality plots

sub_category_order <- behav_sub_cat_summary %>%
    dplyr::filter(parent_category == "sociality") %>%
    dplyr::group_by(sub_category) %>%
    dplyr::reframe(n = sum(n_sub_cat)) %>%
    dplyr::arrange(n) %>%
    dplyr::pull(sub_category)

sociality_subcat <- behav_sub_cat_summary %>%
    dplyr::filter(parent_category == "sociality") %>%
    dplyr::select(study_motivation, sub_category, percent_sub_cat, n_sub_cat, percent_parent) %>%
    tidyr::complete(sub_category, study_motivation, fill = list(percent_sub_cat = 0,
        n_sub_cat = 0)) %>%
    dplyr::mutate(sub_category = factor(sub_category, levels = sub_category_order))
beh_sociality_subcat_fig <- sociality_subcat %>%
    dplyr::mutate(percent_sub_cat = round(percent_sub_cat, 3) * 100) %>%
    ggplot(aes(x = sub_category, y = percent_sub_cat, colour = study_motivation,
        fill = study_motivation, group = study_motivation)) + geom_col(position = position_dodge(width = 0.8),
    width = 0.1) + geom_point(position = position_dodge(width = 0.8), size = 3) +
    geom_text(aes(label = percent_sub_cat), hjust = -0.6, size = 3.5, color = "black",
        position = position_dodge(width = 0.8)) + scale_colour_manual(values = motivation_colour_theme,
    name = "Study motivation") + scale_fill_manual(values = motivation_colour_theme,
    name = "Study motivation") + theme_classic() + coord_flip() + labs(x = "", y = "Percentage of data") +
    theme(legend.position = "none")

beh_sociality_subcat_fig

n_subcat <- sociality_subcat %>%
    dplyr::distinct(sub_category) %>%
    nrow(.)/10

setwd(figures_path)
ggsave("beh_sociality_subcat_fig.pdf", plot = beh_sociality_subcat_fig, width = 10,
    height = 11.7 * n_subcat)

14.2.9 Cognition plots

sub_category_order <- behav_sub_cat_summary %>%
    dplyr::filter(parent_category == "cognition") %>%
    dplyr::group_by(sub_category) %>%
    dplyr::reframe(n = sum(n_sub_cat)) %>%
    dplyr::arrange(n) %>%
    dplyr::pull(sub_category)

cognition_subcat <- behav_sub_cat_summary %>%
    dplyr::filter(parent_category == "cognition") %>%
    dplyr::select(study_motivation, sub_category, percent_sub_cat, n_sub_cat, percent_parent) %>%
    tidyr::complete(sub_category, study_motivation, fill = list(percent_sub_cat = 0,
        n_sub_cat = 0)) %>%
    dplyr::mutate(sub_category = factor(sub_category, levels = sub_category_order))
beh_cognition_subcat_fig <- cognition_subcat %>%
    dplyr::mutate(percent_sub_cat = round(percent_sub_cat, 3) * 100) %>%
    ggplot(aes(x = sub_category, y = percent_sub_cat, colour = study_motivation,
        fill = study_motivation, group = study_motivation)) + geom_col(position = position_dodge(width = 0.8),
    width = 0.1) + geom_point(position = position_dodge(width = 0.8), size = 3) +
    geom_text(aes(label = percent_sub_cat), hjust = -0.6, size = 3.5, color = "black",
        position = position_dodge(width = 0.8)) + scale_colour_manual(values = motivation_colour_theme,
    name = "Study motivation") + scale_fill_manual(values = motivation_colour_theme,
    name = "Study motivation") + theme_classic() + coord_flip() + labs(x = "", y = "Percentage of data") +
    theme(legend.position = "none")

beh_cognition_subcat_fig

n_subcat <- cognition_subcat %>%
    dplyr::distinct(sub_category) %>%
    nrow(.)/10

setwd(figures_path)
ggsave("beh_cognition_subcat_fig.pdf", plot = beh_cognition_subcat_fig, width = 10,
    height = 11.7 * n_subcat)

14.2.10 Non-categories plots

sub_category_order <- behav_sub_cat_summary %>%
    dplyr::filter(parent_category == "noncat") %>%
    dplyr::group_by(sub_category) %>%
    dplyr::reframe(n = sum(n_sub_cat)) %>%
    dplyr::arrange(n) %>%
    dplyr::pull(sub_category)

noncat_subcat <- behav_sub_cat_summary %>%
    dplyr::filter(parent_category == "noncat") %>%
    dplyr::select(study_motivation, sub_category, percent_sub_cat, n_sub_cat, percent_parent) %>%
    tidyr::complete(sub_category, study_motivation, fill = list(percent_sub_cat = 0,
        n_sub_cat = 0)) %>%
    dplyr::mutate(sub_category = factor(sub_category, levels = sub_category_order))
beh_noncat_subcat_fig <- noncat_subcat %>%
    dplyr::mutate(percent_sub_cat = round(percent_sub_cat, 3) * 100) %>%
    ggplot(aes(x = sub_category, y = percent_sub_cat, colour = study_motivation,
        fill = study_motivation, group = study_motivation)) + geom_col(position = position_dodge(width = 0.8),
    width = 0.1) + geom_point(position = position_dodge(width = 0.8), size = 3) +
    geom_text(aes(label = percent_sub_cat), hjust = -0.6, size = 3.5, color = "black",
        position = position_dodge(width = 0.8)) + scale_colour_manual(values = motivation_colour_theme,
    name = "Study motivation") + scale_fill_manual(values = motivation_colour_theme,
    name = "Study motivation") + theme_classic() + coord_flip() + labs(x = "", y = "Percentage of data") +
    theme(legend.position = "none")

beh_noncat_subcat_fig

n_subcat <- noncat_subcat %>%
    dplyr::distinct(sub_category) %>%
    nrow(.)/10

setwd(figures_path)
ggsave("beh_noncat_subcat_fig.pdf", plot = beh_noncat_subcat_fig, width = 10, height = 11.7 *
    n_subcat)

14.3 Behaviour location

Check where behaviour was meassured.

behav_location_summary <- EIPAAB_database %>%
    dplyr::group_by(study_motivation, behav_test_location) %>%
    dplyr::reframe(n = n()) %>%
    tidyr::separate_rows(behav_test_location, sep = ";") %>%
    dplyr::group_by(study_motivation, behav_test_location) %>%
    dplyr::reframe(n = sum(n)) %>%
    tidyr::complete(behav_test_location, study_motivation, fill = list(n = 0)) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_motivation = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round(n/total_motivation * 100, 1)) %>%
    dplyr::select(-total_motivation)

behav_location_overall <- behav_location_summary %>%
    dplyr::group_by(behav_test_location) %>%
    dplyr::reframe(n = sum(n)) %>%
    dplyr::mutate(percent = round(n/sum(n) * 100, 1), study_motivation = "Overall")

behav_location_summary <- rbind(behav_location_overall, behav_location_summary) %>%
    dplyr::arrange(study_motivation)

behav_location_summary
## # A tibble: 12 × 4
##    behav_test_location                                n percent study_motivation
##    <chr>                                          <int>   <dbl> <chr>           
##  1 indoor laboratory setting or assumed indoors     363    99.7 Basic research  
##  2 outdoor natural setting                            1     0.3 Basic research  
##  3 outdoor restricted setting (cannot interact w…     0     0   Basic research  
##  4 indoor laboratory setting or assumed indoors     852    98.7 Environmental   
##  5 outdoor natural setting                            8     0.9 Environmental   
##  6 outdoor restricted setting (cannot interact w…     3     0.3 Environmental   
##  7 indoor laboratory setting or assumed indoors     519    99.6 Medical         
##  8 outdoor natural setting                            1     0.2 Medical         
##  9 outdoor restricted setting (cannot interact w…     1     0.2 Medical         
## 10 indoor laboratory setting or assumed indoors    1734    99.2 Overall         
## 11 outdoor natural setting                           10     0.6 Overall         
## 12 outdoor restricted setting (cannot interact w…     4     0.2 Overall

14.4 Social context

Check how often behaviour was measured in a social context

behav_social_context_summary <- EIPAAB_database %>%
    dplyr::group_by(study_motivation, behav_is_social_context) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_motivation = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round(n/total_motivation * 100, 1)) %>%
    dplyr::select(-total_motivation)

behav_social_context_overall <- behav_social_context_summary %>%
    dplyr::group_by(behav_is_social_context) %>%
    dplyr::reframe(n = sum(n)) %>%
    dplyr::mutate(percent = round(n/sum(n) * 100, 1), study_motivation = "Overall")

behav_social_context_summary <- rbind(behav_social_context_overall, behav_social_context_summary) %>%
    dplyr::arrange(study_motivation)

behav_social_context_summary
## # A tibble: 8 × 4
##   behav_is_social_context     n percent study_motivation
##   <chr>                   <int>   <dbl> <chr>           
## 1 no                        287    79.1 Basic research  
## 2 yes                        76    20.9 Basic research  
## 3 no                        634    73.9 Environmental   
## 4 yes                       224    26.1 Environmental   
## 5 no                        444    85.5 Medical         
## 6 yes                        75    14.5 Medical         
## 7 no                       1365    78.4 Overall         
## 8 yes                       375    21.6 Overall

14.5 Check how behaviour was meassured

Check how often behaviour was meassured in a social context

behav_behav_scoring_summary <- EIPAAB_database %>%
    dplyr::group_by(article_id) %>%
    dplyr::sample_n(1) %>%
    dplyr::ungroup() %>%
    dplyr::group_by(study_motivation, validity_behav_scoring_method) %>%
    dplyr::reframe(n = n()) %>%
    tidyr::separate_rows(validity_behav_scoring_method, sep = ";") %>%
    dplyr::group_by(study_motivation, validity_behav_scoring_method) %>%
    dplyr::reframe(n = sum(n)) %>%
    tidyr::complete(validity_behav_scoring_method, study_motivation, fill = list(n = 0)) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_motivation = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round(n/total_motivation * 100, 1)) %>%
    dplyr::select(-total_motivation)

behav_behav_scoring_overall <- behav_behav_scoring_summary %>%
    dplyr::group_by(validity_behav_scoring_method) %>%
    dplyr::reframe(n = sum(n)) %>%
    dplyr::mutate(percent = round(n/sum(n) * 100, 1), study_motivation = "Overall")

behav_behav_scoring_summary <- rbind(behav_behav_scoring_overall, behav_behav_scoring_summary) %>%
    dplyr::arrange(study_motivation)

behav_behav_scoring_summary
## # A tibble: 32 × 4
##    validity_behav_scoring_method                    n percent study_motivation
##    <chr>                                        <int>   <dbl> <chr>           
##  1 acoustic analysis software                       0     0   Basic research  
##  2 live scoring in real time                       17    10   Basic research  
##  3 manual or human scoring from videos or image    43    25.3 Basic research  
##  4 not specified                                   35    20.6 Basic research  
##  5 other                                            0     0   Basic research  
##  6 quantifying food consumption                     2     1.2 Basic research  
##  7 sensory for physical movement                    2     1.2 Basic research  
##  8 supervised automated tracking approaches        71    41.8 Basic research  
##  9 acoustic analysis software                       1     0.2 Environmental   
## 10 live scoring in real time                       52     9.6 Environmental   
## # ℹ 22 more rows
behav_behav_scoring_summary %>%
    dplyr::filter(study_motivation == "Overall")
## # A tibble: 8 × 4
##   validity_behav_scoring_method                    n percent study_motivation
##   <chr>                                        <int>   <dbl> <chr>           
## 1 acoustic analysis software                       1     0.1 Overall         
## 2 live scoring in real time                       84     8.6 Overall         
## 3 manual or human scoring from videos or image   259    26.6 Overall         
## 4 not specified                                  221    22.7 Overall         
## 5 other                                            1     0.1 Overall         
## 6 quantifying food consumption                    21     2.2 Overall         
## 7 sensory for physical movement                    7     0.7 Overall         
## 8 supervised automated tracking approaches       378    38.9 Overall

15 Linking PICO

Making a dataframe for a flow diagram (sankey plot)

PICO_df <- EIPAAB_database %>%
    dplyr::mutate(behav_cat = case_when(behav_movement_boolean == 1 ~ "Movement",
        behav_boldness_boolean == 1 ~ "Boldness", behav_foraging_boolean == 1 ~ "Foraging",
        behav_antipredator_boolean == 1 ~ "Antipredator", behav_mating_boolean ==
            1 ~ "Mating", behav_post_mating_boolean == 1 ~ "Post mating", behav_agression_boolean ==
            1 ~ "Agression", behav_sociality_boolean == 1 ~ "Sociality", behav_cognition_boolean ==
            1 ~ "Cognition", behav_noncat_boolean == 1 ~ "Not categorised", )) %>%
    dplyr::select(study_motivation, compound_name, compound_atc_level_3, species_name,
        species_class, behav_cat)

Let’s look at the 10 most common classes and ATCs

PICO_class_atc <- PICO_df %>%
    dplyr::filter(!is.na(compound_atc_level_3), !is.na(species_class)) %>%
    tidyr::separate_rows(compound_atc_level_3, sep = ";") %>%
    dplyr::mutate(compound_atc_level_3 = str_trim(compound_atc_level_3))

PICO_atc_10 <- PICO_class_atc %>%
    dplyr::group_by(compound_atc_level_3) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::arrange(desc(n)) %>%
    dplyr::slice(1:10) %>%
    dplyr::pull(compound_atc_level_3)

PICO_class_10 <- PICO_class_atc %>%
    dplyr::group_by(species_class) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::arrange(desc(n)) %>%
    dplyr::slice(1:10) %>%
    dplyr::pull(species_class)

PICO_class_10 <- PICO_class_atc %>%
    dplyr::group_by(species_class) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::arrange(desc(n)) %>%
    dplyr::slice(1:10) %>%
    dplyr::pull(species_class)


behav_cat_order <- PICO_class_atc %>%
    dplyr::filter(compound_atc_level_3 %in% PICO_atc_10 & species_class %in% PICO_class_10) %>%
    dplyr::group_by(behav_cat) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::arrange(desc(n)) %>%
    dplyr::pull(behav_cat)


PICO_class_atc_10 <- PICO_class_atc %>%
    dplyr::filter(compound_atc_level_3 %in% PICO_atc_10 & species_class %in% PICO_class_10) %>%
    dplyr::mutate(compound_atc_level_3 = factor(compound_atc_level_3, levels = PICO_atc_10),
        species_class = factor(species_class, levels = PICO_class_10), behav_cat = factor(behav_cat,
            levels = behav_cat_order)) %>%
    dplyr::select(compound_atc_level_3, behav_cat, species_class)
PICO_atc_class_sankey <- highcharter::hchart(data_to_sankey(PICO_class_atc_10), "sankey")
PICO_atc_class_sankey
setwd(figures_path)
htmlwidgets::saveWidget(widget = PICO_atc_class_sankey, file = "PICO_atc_class_sankey.html")
setwd(figures_path)
# Make a webshot in pdf : high quality but can not choose printed zone
webshot::webshot("PICO_atc_class_sankey.html", "PICO_atc_class_sankey.pdf", delay = 10)

15.1 Common compounds

Lets take a closer look at the 3 most common compounds

EIPAAB_database %>%
    dplyr::group_by(compound_name) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::arrange(desc(n)) %>%
    dplyr::slice(1:3)
## # A tibble: 3 × 2
##   compound_name                 n
##   <chr>                     <int>
## 1 Fluoxetine                  201
## 2 Diazepam                     67
## 3 17-alpha-ethinylestradiol    63

15.1.1 Fluoxetine

spp_order <- PICO_df %>%
    dplyr::filter(compound_name == "Fluoxetine") %>%
    dplyr::group_by(species_name) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::arrange(desc(n)) %>%
    dplyr::slice(1:5) %>%
    pull(species_name)

beh_order <- PICO_df %>%
    dplyr::filter(compound_name == "Fluoxetine" & species_name %in% spp_order) %>%
    dplyr::group_by(behav_cat) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::arrange(desc(n)) %>%
    pull(behav_cat)

PICO_fluoxetine <- PICO_df %>%
    dplyr::filter(compound_name == "Fluoxetine" & species_name %in% spp_order) %>%
    dplyr::mutate(species_name = factor(species_name, levels = spp_order), behav_cat = factor(behav_cat,
        levels = beh_order), ) %>%
    dplyr::select(species_name, behav_cat)
PICO_fluoxetine %>%
    dplyr::filter(species_name == "Betta splendens") %>%
    dplyr::distinct(behav_cat)
##   behav_cat
## 1  Boldness
## 2 Agression
## 3    Mating
## 4  Movement
PICO_fluoxetine_sankey <- highcharter::hchart(data_to_sankey(PICO_fluoxetine), "sankey",
    name = "PICO")
PICO_fluoxetine_sankey
setwd(figures_path)
htmlwidgets::saveWidget(widget = PICO_fluoxetine_sankey, file = "PICO_fluoxetine_sankey.html")
setwd(figures_path)
# Make a webshot in pdf : high quality but can not choose printed zone
webshot::webshot("PICO_fluoxetine_sankey.html", "PICO_fluoxetine_sankey.pdf", delay = 10)

15.1.2 Diazepam

spp_order <- PICO_df %>%
    dplyr::filter(compound_name == "Diazepam") %>%
    dplyr::group_by(species_name) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::arrange(desc(n)) %>%
    dplyr::slice(1:5) %>%
    pull(species_name)

beh_order <- PICO_df %>%
    dplyr::filter(compound_name == "Diazepam" & species_name %in% spp_order) %>%
    dplyr::group_by(behav_cat) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::arrange(desc(n)) %>%
    pull(behav_cat)

PICO_diazepam <- PICO_df %>%
    dplyr::filter(compound_name == "Diazepam" & species_name %in% spp_order) %>%
    dplyr::mutate(species_name = factor(species_name, levels = spp_order), behav_cat = factor(behav_cat,
        levels = beh_order), ) %>%
    dplyr::select(species_name, behav_cat)
PICO_diazepam_sankey <- highcharter::hchart(data_to_sankey(PICO_diazepam), "sankey",
    name = "PICO")
PICO_diazepam_sankey
setwd(figures_path)
htmlwidgets::saveWidget(widget = PICO_diazepam_sankey, file = "PICO_diazepam_sankey.html")
setwd(figures_path)
# Make a webshot in pdf : high quality but can not choose printed zone
webshot::webshot("PICO_diazepam_sankey.html", "PICO_diazepam_sankey.pdf", delay = 10)

15.3.1 17-alpha-ethinylestradiol

spp_order <- PICO_df %>%
    dplyr::filter(compound_name == "17-alpha-ethinylestradiol") %>%
    dplyr::group_by(species_name) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::arrange(desc(n)) %>%
    dplyr::slice(1:5) %>%
    pull(species_name)

beh_order <- PICO_df %>%
    dplyr::filter(compound_name == "17-alpha-ethinylestradiol" & species_name %in%
        spp_order) %>%
    dplyr::group_by(behav_cat) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::arrange(desc(n)) %>%
    pull(behav_cat)

PICO_EE2 <- PICO_df %>%
    dplyr::filter(compound_name == "17-alpha-ethinylestradiol" & species_name %in%
        spp_order) %>%
    dplyr::mutate(species_name = factor(species_name, levels = spp_order), behav_cat = factor(behav_cat,
        levels = beh_order), ) %>%
    dplyr::select(species_name, behav_cat)
PICO_EE2_sankey <- highcharter::hchart(data_to_sankey(PICO_EE2), "sankey", name = "PICO")
PICO_EE2_sankey
setwd(figures_path)
htmlwidgets::saveWidget(widget = PICO_EE2_sankey, file = "PICO_EE2_sankey.html")
setwd(figures_path)
# Make a webshot in pdf : high quality but can not choose printed zone
webshot::webshot("PICO_EE2_sankey.html", "PICO_EE2_sankey.pdf", delay = 10)

16 Knowledge clusters and gaps

Identify knowledge clusters and gaps.

We will also do this by study motivation, because the knowleage gaps will be motivation spesfic.

16.1 Species class

First look by species class

Making a dataframe

behav_cat_class_long <- PICO_df %>%
    dplyr::group_by(study_motivation, species_class, behav_cat) %>%
    dplyr::reframe(count = n()) %>%
    tidyr::complete(study_motivation, species_class, behav_cat, fill = list(count = 0)) %>%
    dplyr::group_by(study_motivation, species_class) %>%
    dplyr::mutate(total_class_motivation = sum(count)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(rel_percent = round(count/total_class_motivation * 100, 0), rel_percent = if_else(is.finite(rel_percent),
        rel_percent, 0))

class_order <- behav_cat_class_long %>%
    dplyr::group_by(species_class) %>%
    dplyr::reframe(n = sum(count)) %>%
    dplyr::arrange(n) %>%
    dplyr::pull(species_class)

behav_cat_order <- behav_cat_class_long %>%
    dplyr::group_by(behav_cat) %>%
    dplyr::reframe(n = sum(count)) %>%
    dplyr::arrange(desc(n)) %>%
    dplyr::pull(behav_cat)

behav_cat_class_long <- behav_cat_class_long %>%
    dplyr::mutate(species_class = factor(species_class, levels = class_order), behav_cat = factor(behav_cat,
        levels = behav_cat_order))
cust_col <- colorRampPalette(c("#FDEDF4", "#F068A7"))(30)

behav_class_hm <- behav_cat_class_long %>%
    ggplot(aes(x = behav_cat, y = species_class, fill = count)) + geom_tile() + scale_fill_gradientn(colors = cust_col,
    na.value = "white", limits = c(1, max(behav_cat_class_long$count, na.rm = TRUE)),
    guide = "none") + theme_bw() + facet_wrap(~study_motivation) + theme(axis.text.x = element_text(angle = 45,
    hjust = 1)) + labs(x = "Behaviour", y = "Species Class", fill = "Count")
behav_class_hm

setwd(figures_path)
ggsave("behav_class_hm.pdf", plot = behav_class_hm, width = 8.3, height = 11.7/2)

This one uses relative vaules for each class (e.g. row in the heat map)

cust_col <- colorRampPalette(brewer.pal(4, "Oranges"))(30)

behav_class_rel_hm <- behav_cat_class_long %>%
    ggplot(aes(x = behav_cat, y = species_class, fill = rel_percent)) + geom_tile() +
    # geom_text(aes(label = ifelse(rel_percent == 0, NA, rel_percent)), color =
    # 'black', size = 3) +
scale_fill_gradientn(colors = cust_col, na.value = "white", limits = c(1, max(behav_cat_class_long$count,
    na.rm = TRUE)), guide = "none") + theme_bw() + facet_wrap(~study_motivation) +
    theme(axis.text.x = element_text(angle = 45, hjust = 1)) + labs(x = "Behaviour",
    y = "Species Class", fill = "Count")
behav_class_rel_hm

setwd(figures_path)
ggsave("behav_class_rel_hm.pdf", plot = behav_class_rel_hm, width = 8.3, height = 11.7/2)

16.2 Compound cluster/gaps

Now looking by compound

Making a dataframe

behav_atc_long <- PICO_df %>%
    separate_rows(compound_atc_level_3, sep = ";") %>%
    dplyr::group_by(study_motivation, compound_atc_level_3, behav_cat) %>%
    dplyr::reframe(count = n()) %>%
    tidyr::complete(study_motivation, compound_atc_level_3, behav_cat, fill = list(count = 0)) %>%
    dplyr::group_by(study_motivation, compound_atc_level_3) %>%
    dplyr::mutate(total_atc_motivation = sum(count)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(rel_percent = round(count/total_atc_motivation * 100, 0), rel_percent = if_else(is.finite(rel_percent),
        rel_percent, 0))

atc_order <- behav_atc_long %>%
    dplyr::group_by(compound_atc_level_3) %>%
    dplyr::reframe(n = sum(count)) %>%
    dplyr::arrange(n) %>%
    dplyr::pull(compound_atc_level_3)

behav_cat_order <- behav_atc_long %>%
    dplyr::group_by(behav_cat) %>%
    dplyr::reframe(n = sum(count)) %>%
    dplyr::arrange(desc(n)) %>%
    dplyr::pull(behav_cat)

behav_atc_long <- behav_atc_long %>%
    dplyr::mutate(compound_atc_level_3 = factor(compound_atc_level_3, levels = atc_order),
        behav_cat = factor(behav_cat, levels = behav_cat_order))

There are 132 ATC level 3 codes. So the plot below is not going to be very informative. It could be useful if you are only interested in a few ATC groups.

behav_atc_long %>%
    dplyr::distinct(compound_atc_level_3) %>%
    nrow()
## [1] 132
cust_col <- colorRampPalette(c("#FDEDF4", "#F068A7"))(30)

behav_atc_hm <- behav_atc_long %>%
    ggplot(aes(x = behav_cat, y = compound_atc_level_3, fill = count)) + geom_tile() +
    # geom_text(aes(label = ifelse(count == 0, NA, count)), color = 'black',
    # size = 3) +
scale_fill_gradientn(colors = cust_col, na.value = "white", limits = c(1, max(behav_atc_long$count,
    na.rm = TRUE)), guide = "none") + theme_void() + facet_wrap(~study_motivation) +
    theme(axis.text.x = element_text(angle = 45, hjust = 1)) + labs(x = "Behaviour",
    y = "Species Class", fill = "Count")
behav_atc_hm

setwd(figures_path)
ggsave("behav_atc_hm.pdf", plot = behav_atc_hm, width = 8.3, height = 11.7/2)

17 Additional biomarkers

EIPAAB_database %>%
    dplyr::group_by(article_id) %>%
    dplyr::sample_n(1) %>%
    dplyr::group_by(additional_biomarkers) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::mutate(total = sum(n), percent = n/total)
## # A tibble: 2 × 4
##   additional_biomarkers     n total percent
##   <chr>                 <int> <int>   <dbl>
## 1 No                      435   901   0.483
## 2 Yes                     466   901   0.517
EIPAAB_database %>%
    dplyr::group_by(article_id) %>%
    dplyr::sample_n(1) %>%
    dplyr::group_by(validity_survival_growth_reproduction) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::mutate(total = sum(n), percent = n/total)
## # A tibble: 2 × 4
##   validity_survival_growth_reproduction     n total percent
##   <chr>                                 <int> <int>   <dbl>
## 1 No                                      543   901   0.603
## 2 Yes                                     358   901   0.397

18 Validity

This a list of all 19 metadata that relate to our validity information.

c(“validity_guideline”, “validity_good_laboratory_practice”, “validity_survival_growth_reproduction”, “validity_animal_feeding”, “validity_water_quality”, “validity_light_cycle”, “validity_randomization”, “validity_behav_scoring_method”, “validity_behav_blinding”, “validity_conflict_statement”, “species_source”, “species_stage”, “species_sex”, “compound_min_duration_exposure”, “compound_max_duration_exposure”, “validity_compound_cas_reported”, “validity_compound_purity_reported”, “validity_compound_water_verification”, “validity_compound_animal_verification”)

18.1 Did it follow a guideline (CRED Q1)

guideline <- EIPAAB_database %>%
    dplyr::group_by(article_id) %>%
    dplyr::sample_n(1) %>%
    dplyr::ungroup() %>%
    dplyr::group_by(validity_guideline, study_motivation) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_motivation = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round(n/total_motivation * 100, 1)) %>%
    dplyr::select(-total_motivation)

guideline_all <- guideline %>%
    dplyr::group_by(validity_guideline) %>%
    dplyr::reframe(n = sum(n)) %>%
    dplyr::mutate(study_motivation = "Overall", percent = round(n/sum(n) * 100, 1))


guideline_all <- rbind(guideline_all, guideline) %>%
    dplyr::filter(validity_guideline == "Yes")
guideline_all
## # A tibble: 4 × 4
##   validity_guideline     n study_motivation percent
##   <chr>              <int> <chr>              <dbl>
## 1 Yes                  135 Overall             15  
## 2 Yes                  111 Environmental       21.8
## 3 Yes                   14 Medical              6  
## 4 Yes                   10 Basic research       6.3

18.2 Did it use good laboratory practice (CRED Q2)

GLP <- EIPAAB_database %>%
    dplyr::group_by(article_id) %>%
    dplyr::sample_n(1) %>%
    dplyr::ungroup() %>%
    dplyr::group_by(validity_good_laboratory_practice, study_motivation) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_motivation = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round(n/total_motivation * 100, 1)) %>%
    dplyr::select(-total_motivation)

GLP_all <- GLP %>%
    dplyr::group_by(validity_good_laboratory_practice) %>%
    dplyr::reframe(n = sum(n)) %>%
    dplyr::mutate(study_motivation = "Overall", percent = round(n/sum(n) * 100, 1))


GLP_all <- rbind(GLP_all, GLP) %>%
    dplyr::filter(validity_good_laboratory_practice == "Yes")
GLP_all
## # A tibble: 3 × 4
##   validity_good_laboratory_practice     n study_motivation percent
##   <chr>                             <int> <chr>              <dbl>
## 1 Yes                                   6 Overall              0.7
## 2 Yes                                   5 Environmental        1  
## 3 Yes                                   1 Medical              0.4

18.3 Did it report survival, growth and/or reproduction (CRED Q3)

survival_growth_reproduction <- EIPAAB_database %>%
    dplyr::group_by(article_id) %>%
    dplyr::sample_n(1) %>%
    dplyr::ungroup() %>%
    dplyr::group_by(validity_survival_growth_reproduction, study_motivation) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_motivation = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round(n/total_motivation * 100, 1)) %>%
    dplyr::select(-total_motivation)

survival_growth_reproduction_all <- survival_growth_reproduction %>%
    dplyr::group_by(validity_survival_growth_reproduction) %>%
    dplyr::reframe(n = sum(n)) %>%
    dplyr::mutate(study_motivation = "Overall", percent = round(n/sum(n) * 100, 1))


survival_growth_reproduction_all <- rbind(survival_growth_reproduction_all, survival_growth_reproduction) %>%
    dplyr::filter(validity_survival_growth_reproduction == "Yes")
survival_growth_reproduction_all
## # A tibble: 4 × 4
##   validity_survival_growth_reproduction     n study_motivation percent
##   <chr>                                 <int> <chr>              <dbl>
## 1 Yes                                     358 Overall             39.7
## 2 Yes                                     273 Environmental       53.5
## 3 Yes                                      61 Medical             26.1
## 4 Yes                                      24 Basic research      15.3

18.4 Did it report compound cas (CRED Q5)

CAS <- EIPAAB_database %>%
    dplyr::group_by(article_id) %>%
    dplyr::sample_n(1) %>%
    dplyr::ungroup() %>%
    dplyr::group_by(validity_compound_cas_reported, study_motivation) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_motivation = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round(n/total_motivation * 100, 1)) %>%
    dplyr::select(-total_motivation)

CAS_all <- CAS %>%
    dplyr::group_by(validity_compound_cas_reported) %>%
    dplyr::reframe(n = sum(n)) %>%
    dplyr::mutate(study_motivation = "Overall", percent = round(n/sum(n) * 100, 1))


CAS_all <- rbind(CAS_all, CAS) %>%
    dplyr::filter(validity_compound_cas_reported == "Yes")
CAS_all
## # A tibble: 4 × 4
##   validity_compound_cas_reported     n study_motivation percent
##   <chr>                          <int> <chr>              <dbl>
## 1 Yes                              223 Overall             24.8
## 2 Yes                              186 Environmental       36.5
## 3 Yes                               25 Medical             10.7
## 4 Yes                               12 Basic research       7.6

18.5 Did it report compound purity (CRED Q6)

purity <- EIPAAB_database %>%
    dplyr::group_by(article_id) %>%
    dplyr::sample_n(1) %>%
    dplyr::ungroup() %>%
    dplyr::group_by(validity_compound_purity_reported, study_motivation) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_motivation = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round(n/total_motivation * 100, 1)) %>%
    dplyr::select(-total_motivation)

purity_all <- purity %>%
    dplyr::group_by(validity_compound_purity_reported) %>%
    dplyr::reframe(n = sum(n)) %>%
    dplyr::mutate(study_motivation = "Overall", percent = round(n/sum(n) * 100, 1))


purity_all <- rbind(purity_all, purity) %>%
    dplyr::filter(validity_compound_purity_reported == "Yes")
purity_all
## # A tibble: 4 × 4
##   validity_compound_purity_reported     n study_motivation percent
##   <chr>                             <int> <chr>              <dbl>
## 1 Yes                                 227 Overall             25.2
## 2 Yes                                 197 Environmental       38.6
## 3 Yes                                  21 Medical              9  
## 4 Yes                                   9 Basic research       5.7

18.6 Species infomartion (CRED Q8)

18.6.1 Life stage

stage <- EIPAAB_database %>%
    dplyr::group_by(unique_population_id) %>%
    dplyr::sample_n(1) %>%
    dplyr::ungroup() %>%
    dplyr::group_by(species_stage, study_motivation) %>%
    dplyr::reframe(n = n()) %>%
    tidyr::separate_rows(species_stage, sep = ";") %>%
    dplyr::group_by(species_stage, study_motivation) %>%
    dplyr::reframe(n = sum(n)) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_motivation = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round(n/total_motivation * 100, 1)) %>%
    dplyr::select(-total_motivation)

stage_all <- stage %>%
    dplyr::group_by(species_stage) %>%
    dplyr::reframe(n = sum(n)) %>%
    dplyr::mutate(study_motivation = "Overall", percent = round(n/sum(n) * 100, 1))


stage_all <- rbind(stage_all, stage) %>%
    dplyr::filter(species_stage == "Unknown or not specified") %>%
    dplyr::mutate(percent_reported = 100 - percent)
stage_all
## # A tibble: 4 × 5
##   species_stage                n study_motivation percent percent_reported
##   <chr>                    <int> <chr>              <dbl>            <dbl>
## 1 Unknown or not specified   166 Overall             16.6             83.4
## 2 Unknown or not specified   100 Environmental       17.1             82.9
## 3 Unknown or not specified    22 Medical              9               91  
## 4 Unknown or not specified    44 Basic research      26.5             73.5

18.6.1 Sex

sex <- EIPAAB_database %>%
    dplyr::group_by(unique_population_id) %>%
    dplyr::sample_n(1) %>%
    dplyr::ungroup() %>%
    dplyr::group_by(species_sex, study_motivation) %>%
    dplyr::reframe(n = n()) %>%
    tidyr::separate_rows(species_sex, sep = ";") %>%
    dplyr::group_by(species_sex, study_motivation) %>%
    dplyr::reframe(n = sum(n)) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_motivation = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round(n/total_motivation * 100, 1)) %>%
    dplyr::select(-total_motivation)

sex_all <- sex %>%
    dplyr::group_by(species_sex) %>%
    dplyr::reframe(n = sum(n)) %>%
    dplyr::mutate(study_motivation = "Overall", percent = round(n/sum(n) * 100, 1))


sex_all <- rbind(sex_all, sex) %>%
    dplyr::filter(species_sex == "Unknown or not specified") %>%
    dplyr::mutate(percent_reported = 100 - percent)
sex_all
## # A tibble: 4 × 5
##   species_sex                  n study_motivation percent percent_reported
##   <chr>                    <int> <chr>              <dbl>            <dbl>
## 1 Unknown or not specified   546 Overall             46.5             53.5
## 2 Unknown or not specified   325 Environmental       50.4             49.6
## 3 Unknown or not specified   132 Medical             41               59  
## 4 Unknown or not specified    89 Basic research      43.2             56.8

18.7 The soruce of species (CRED Q9)

source <- EIPAAB_database %>%
    dplyr::group_by(unique_population_id) %>%
    dplyr::sample_n(1) %>%
    dplyr::ungroup() %>%
    dplyr::group_by(species_source, study_motivation) %>%
    dplyr::reframe(n = n()) %>%
    tidyr::separate_rows(species_source, sep = ";") %>%
    dplyr::group_by(species_source, study_motivation) %>%
    dplyr::reframe(n = sum(n)) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_motivation = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round(n/total_motivation * 100, 1)) %>%
    dplyr::select(-total_motivation)

source_all <- source %>%
    dplyr::group_by(species_source) %>%
    dplyr::reframe(n = sum(n)) %>%
    dplyr::mutate(study_motivation = "Overall", percent = round(n/sum(n) * 100, 1))


source_all <- rbind(source_all, source) %>%
    dplyr::filter(species_source == "Not reported") %>%
    dplyr::mutate(percent_reported = 100 - percent)
source_all
## # A tibble: 4 × 5
##   species_source     n study_motivation percent percent_reported
##   <chr>          <int> <chr>              <dbl>            <dbl>
## 1 Not reported     148 Overall             15.6             84.4
## 2 Not reported      72 Environmental       13.1             86.9
## 3 Not reported      51 Medical             21.2             78.8
## 4 Not reported      25 Basic research      15.5             84.5

18.8 experimental system (CRED Q11)

18.8.1 Feeding

feeding <- EIPAAB_database %>%
    dplyr::group_by(article_id) %>%
    dplyr::sample_n(1) %>%
    dplyr::ungroup() %>%
    dplyr::group_by(validity_animal_feeding, study_motivation) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_motivation = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round(n/total_motivation * 100, 1)) %>%
    dplyr::select(-total_motivation)

feeding_all <- feeding %>%
    dplyr::group_by(validity_animal_feeding) %>%
    dplyr::reframe(n = sum(n)) %>%
    dplyr::mutate(study_motivation = "Overall", percent = round(n/sum(n) * 100, 1))


feeding_all <- rbind(feeding_all, feeding) %>%
    dplyr::filter(validity_animal_feeding == "Yes")
feeding_all
## # A tibble: 4 × 4
##   validity_animal_feeding     n study_motivation percent
##   <chr>                   <int> <chr>              <dbl>
## 1 Yes                       716 Overall             79.5
## 2 Yes                       430 Environmental       84.3
## 3 Yes                       159 Medical             68.2
## 4 Yes                       127 Basic research      80.4

18.8.1 Water quality

water <- EIPAAB_database %>%
    dplyr::group_by(article_id) %>%
    dplyr::sample_n(1) %>%
    dplyr::ungroup() %>%
    dplyr::group_by(validity_water_quality, study_motivation) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_motivation = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round(n/total_motivation * 100, 1)) %>%
    dplyr::select(-total_motivation)

water_all <- water %>%
    dplyr::group_by(validity_water_quality) %>%
    dplyr::reframe(n = sum(n)) %>%
    dplyr::mutate(study_motivation = "Overall", percent = round(n/sum(n) * 100, 1))


water_all <- rbind(water_all, water) %>%
    dplyr::filter(validity_water_quality == "Yes")
water_all
## # A tibble: 4 × 4
##   validity_water_quality     n study_motivation percent
##   <chr>                  <int> <chr>              <dbl>
## 1 Yes                      806 Overall             89.5
## 2 Yes                      473 Environmental       92.7
## 3 Yes                      206 Medical             88.4
## 4 Yes                      127 Basic research      80.4

18.8.1 light cycle

light <- EIPAAB_database %>%
    dplyr::group_by(article_id) %>%
    dplyr::sample_n(1) %>%
    dplyr::ungroup() %>%
    dplyr::group_by(validity_light_cycle, study_motivation) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_motivation = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round(n/total_motivation * 100, 1)) %>%
    dplyr::select(-total_motivation)

light_all <- light %>%
    dplyr::group_by(validity_light_cycle) %>%
    dplyr::reframe(n = sum(n)) %>%
    dplyr::mutate(study_motivation = "Overall", percent = round(n/sum(n) * 100, 1))


light_all <- rbind(light_all, light) %>%
    dplyr::filter(validity_light_cycle == "Yes")
light_all
## # A tibble: 4 × 4
##   validity_light_cycle     n study_motivation percent
##   <chr>                <int> <chr>              <dbl>
## 1 Yes                    756 Overall             83.9
## 2 Yes                    429 Environmental       84.1
## 3 Yes                    200 Medical             85.8
## 4 Yes                    127 Basic research      80.4

18.9 Exposure duration (CRED Q14)

18.9.1 Minimum duration

min_duration <- EIPAAB_database %>%
    dplyr::group_by(compound_min_duration_exposure, study_motivation) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_motivation = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round(n/total_motivation * 100, 1)) %>%
    dplyr::select(-total_motivation)

min_duration_all <- min_duration %>%
    dplyr::group_by(compound_min_duration_exposure) %>%
    dplyr::reframe(n = sum(n)) %>%
    dplyr::mutate(study_motivation = "Overall", percent = round(n/sum(n) * 100, 1))


min_duration_all <- rbind(min_duration_all, min_duration) %>%
    dplyr::filter(compound_min_duration_exposure == "Not stated") %>%
    dplyr::mutate(percent_reported = 100 - percent)
min_duration_all
## # A tibble: 4 × 5
##   compound_min_duration_exposure     n study_motivation percent percent_reported
##   <chr>                          <int> <chr>              <dbl>            <dbl>
## 1 Not stated                       102 Overall              5.9             94.1
## 2 Not stated                        38 Environmental        4.4             95.6
## 3 Not stated                        52 Medical             10               90  
## 4 Not stated                        12 Basic research       3.3             96.7

18.9.2 Maximum duration

max_duration <- EIPAAB_database %>%
    dplyr::group_by(compound_max_duration_exposure, study_motivation) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_motivation = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round(n/total_motivation * 100, 1)) %>%
    dplyr::select(-total_motivation)

max_duration_all <- max_duration %>%
    dplyr::group_by(compound_max_duration_exposure) %>%
    dplyr::reframe(n = sum(n)) %>%
    dplyr::mutate(study_motivation = "Overall", percent = round(n/sum(n) * 100, 1))


max_duration_all <- rbind(max_duration_all, max_duration) %>%
    dplyr::filter(compound_max_duration_exposure == "Not stated") %>%
    dplyr::mutate(percent_reported = 100 - percent)
max_duration_all
## # A tibble: 4 × 5
##   compound_max_duration_exposure     n study_motivation percent percent_reported
##   <chr>                          <int> <chr>              <dbl>            <dbl>
## 1 Not stated                        96 Overall              5.5             94.5
## 2 Not stated                        32 Environmental        3.7             96.3
## 3 Not stated                        53 Medical             10.2             89.8
## 4 Not stated                        11 Basic research       3               97

18.10 Exposure verification (CRED Q15)

18.10.1 Water verification

water_verification <- EIPAAB_database %>%
    dplyr::filter(!is.na(validity_compound_water_verification)) %>%
    dplyr::group_by(validity_compound_water_verification, study_motivation) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_motivation = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round(n/total_motivation * 100, 1)) %>%
    dplyr::select(-total_motivation)

water_verification_all <- water_verification %>%
    dplyr::group_by(validity_compound_water_verification) %>%
    dplyr::reframe(n = sum(n)) %>%
    dplyr::mutate(study_motivation = "Overall", percent = round(n/sum(n) * 100, 1))


water_verification_all <- rbind(water_verification_all, water_verification) %>%
    dplyr::filter(validity_compound_water_verification == "Measured")
water_verification_all
## # A tibble: 4 × 4
##   validity_compound_water_verification     n study_motivation percent
##   <chr>                                <int> <chr>              <dbl>
## 1 Measured                               313 Overall             20.6
## 2 Measured                               295 Environmental       35.8
## 3 Measured                                10 Medical              2.5
## 4 Measured                                 8 Basic research       2.7

18.10.1 Tissue verification

tissue_verification <- EIPAAB_database %>%
    # dplyr::filter(!is.na(validity_compound_animal_verification)) %>%
dplyr::group_by(validity_compound_animal_verification, study_motivation) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_motivation = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round(n/total_motivation * 100, 1)) %>%
    dplyr::select(-total_motivation)

tissue_verification_all <- tissue_verification %>%
    dplyr::group_by(validity_compound_animal_verification) %>%
    dplyr::reframe(n = sum(n)) %>%
    dplyr::mutate(study_motivation = "Overall", percent = round(n/sum(n) * 100, 1))


tissue_verification_all <- rbind(tissue_verification_all, tissue_verification) %>%
    dplyr::filter(validity_compound_animal_verification == "Yes")
tissue_verification_all
## # A tibble: 4 × 4
##   validity_compound_animal_verification     n study_motivation percent
##   <chr>                                 <int> <chr>              <dbl>
## 1 Yes                                     154 Overall              8.9
## 2 Yes                                     115 Environmental       13.4
## 3 Yes                                      22 Medical              4.2
## 4 Yes                                      17 Basic research       4.7

18.11 Randomization (Not CRED)

randomization <- EIPAAB_database %>%
    dplyr::group_by(article_id) %>%
    dplyr::sample_n(1) %>%
    dplyr::ungroup() %>%
    dplyr::group_by(validity_randomization, study_motivation) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_motivation = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round(n/total_motivation * 100, 1)) %>%
    dplyr::select(-total_motivation)

randomization_all <- randomization %>%
    dplyr::group_by(validity_randomization) %>%
    dplyr::reframe(n = sum(n)) %>%
    dplyr::mutate(study_motivation = "Overall", percent = round(n/sum(n) * 100, 1))


randomization_all <- rbind(randomization_all, randomization) %>%
    dplyr::filter(validity_randomization == "Yes") %>%
    dplyr::mutate(percent_disclosed = 100 - percent)
randomization_all
## # A tibble: 4 × 5
##   validity_randomization     n study_motivation percent percent_disclosed
##   <chr>                  <int> <chr>              <dbl>             <dbl>
## 1 Yes                      362 Overall             40.2              59.8
## 2 Yes                      229 Environmental       44.9              55.1
## 3 Yes                       75 Medical             32.1              67.9
## 4 Yes                       58 Basic research      36.9              63.1

18.12 Blinding (Not CRED)

blinding <- EIPAAB_database %>%
    dplyr::group_by(article_id) %>%
    dplyr::sample_n(1) %>%
    dplyr::ungroup() %>%
    dplyr::group_by(validity_behav_blinding, study_motivation) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_motivation = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round(n/total_motivation * 100, 1)) %>%
    dplyr::select(-total_motivation)

blinding_all <- blinding %>%
    dplyr::group_by(validity_behav_blinding) %>%
    dplyr::reframe(n = sum(n)) %>%
    dplyr::mutate(study_motivation = "Overall", percent = round(n/sum(n) * 100, 1))


blinding_all <- rbind(blinding_all, blinding) %>%
    dplyr::filter(validity_behav_blinding == "Yes")
blinding_all
## # A tibble: 4 × 4
##   validity_behav_blinding     n study_motivation percent
##   <chr>                   <int> <chr>              <dbl>
## 1 Yes                       153 Overall             17  
## 2 Yes                        75 Environmental       14.7
## 3 Yes                        45 Medical             19.2
## 4 Yes                        33 Basic research      21

18.13 Scoring method (Not CRED)

behav_scoring <- EIPAAB_database %>%
    dplyr::group_by(article_id) %>%
    dplyr::sample_n(1) %>%
    dplyr::ungroup() %>%
    tidyr::separate_rows(validity_behav_scoring_method, sep = ";") %>%
    dplyr::group_by(validity_behav_scoring_method, study_motivation) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_motivation = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round(n/total_motivation * 100, 1)) %>%
    dplyr::select(-total_motivation)

behav_scoring_all <- behav_scoring %>%
    dplyr::group_by(validity_behav_scoring_method) %>%
    dplyr::reframe(n = sum(n)) %>%
    dplyr::mutate(study_motivation = "Overall", percent = round(n/sum(n) * 100, 1))


behav_scoring_all <- rbind(behav_scoring_all, behav_scoring) %>%
    dplyr::filter(validity_behav_scoring_method == "not specified") %>%
    dplyr::mutate(percent_specified = 100 - percent)
behav_scoring_all
## # A tibble: 4 × 5
##   validity_behav_scoring_method     n study_motivation percent percent_specified
##   <chr>                         <int> <chr>              <dbl>             <dbl>
## 1 not specified                   221 Overall             22.7              77.3
## 2 not specified                   130 Environmental       24                76  
## 3 not specified                    56 Medical             21.5              78.5
## 4 not specified                    35 Basic research      20.7              79.3

18.14 Conflict statement (Not CRED)

conflict <- EIPAAB_database %>%
    dplyr::group_by(article_id) %>%
    dplyr::sample_n(1) %>%
    dplyr::ungroup() %>%
    dplyr::group_by(validity_conflict_statement, study_motivation) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_motivation = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round(n/total_motivation * 100, 1)) %>%
    dplyr::select(-total_motivation)

conflict_all <- conflict %>%
    dplyr::group_by(validity_conflict_statement) %>%
    dplyr::reframe(n = sum(n)) %>%
    dplyr::mutate(study_motivation = "Overall", percent = round(n/sum(n) * 100, 1))


conflict_all <- rbind(conflict_all, conflict) %>%
    dplyr::filter(validity_conflict_statement == "No statement is made in the paper") %>%
    dplyr::mutate(percent_specified = 100 - percent)
conflict_all
## # A tibble: 4 × 5
##   validity_conflict_statement       n study_motivation percent percent_specified
##   <chr>                         <int> <chr>              <dbl>             <dbl>
## 1 No statement is made in the …   407 Overall             45.2              54.8
## 2 No statement is made in the …   254 Environmental       49.8              50.2
## 3 No statement is made in the …    65 Medical             27.9              72.1
## 4 No statement is made in the …    88 Basic research      55.7              44.3

19 R Session Informtion

# pander for making it look nicer
sessionInfo() %>%
    pander()

R version 4.2.3 (2023-03-15 ucrt)

Platform: x86_64-w64-mingw32/x64 (64-bit)

locale: LC_COLLATE=English_Australia.utf8, LC_CTYPE=English_Australia.utf8, LC_MONETARY=English_Australia.utf8, LC_NUMERIC=C and LC_TIME=English_Australia.utf8

attached base packages: stats, graphics, grDevices, utils, datasets, methods and base

other attached packages: lmerTest(v.3.1-3), car(v.3.1-2), carData(v.3.0-5), lme4(v.1.1-35.5), Matrix(v.1.5-3), tidybayes(v.3.0.6), emmeans(v.1.10.3), performance(v.0.12.0), rstan(v.2.32.6), StanHeaders(v.2.32.9), brms(v.2.21.0), Rcpp(v.1.0.10), ggthemes(v.4.2.4), here(v.1.0.1), pander(v.0.6.5), highcharter(v.0.9.4), ggdist(v.3.3.2), gridExtra(v.2.3), ape(v.5.8), treeio(v.1.22.0), ggtree(v.3.6.2), RColorBrewer(v.1.1-3), ggrepel(v.0.9.3), igraph(v.1.6.0), ggraph(v.2.1.0), lubridate(v.1.9.2), forcats(v.1.0.0), stringr(v.1.5.0), dplyr(v.1.1.1), purrr(v.1.0.1), readr(v.2.1.4), tidyr(v.1.3.0), tibble(v.3.2.1), ggplot2(v.3.5.1) and tidyverse(v.2.0.0)

loaded via a namespace (and not attached): backports(v.1.4.1), systemfonts(v.1.0.4), lazyeval(v.0.2.2), splines(v.4.2.3), svUnit(v.1.0.6), TH.data(v.1.1-2), rstantools(v.2.4.0), inline(v.0.3.19), digest(v.0.6.31), yulab.utils(v.0.1.4), htmltools(v.0.5.8.1), viridis(v.0.6.5), fansi(v.1.0.4), magrittr(v.2.0.3), checkmate(v.2.3.1), memoise(v.2.0.1), tzdb(v.0.3.0), graphlayouts(v.1.0.2), RcppParallel(v.5.1.8), matrixStats(v.1.3.0), xts(v.0.14.0), sandwich(v.3.1-0), timechange(v.0.2.0), colorspace(v.2.1-0), textshaping(v.0.3.6), xfun(v.0.38), callr(v.3.7.6), jsonlite(v.1.8.4), survival(v.3.5-3), zoo(v.1.8-12), glue(v.1.6.2), polyclip(v.1.10-6), gtable(v.0.3.5), webshot(v.0.5.5), V8(v.4.4.2), distributional(v.0.4.0), pkgbuild(v.1.4.4), quantmod(v.0.4.26), abind(v.1.4-5), scales(v.1.3.0), mvtnorm(v.1.2-5), viridisLite(v.0.4.2), xtable(v.1.8-4), gridGraphics(v.0.5-1), tidytree(v.0.4.6), stats4(v.4.2.3), htmlwidgets(v.1.6.2), arrayhelpers(v.1.1-0), posterior(v.1.6.0), pkgconfig(v.2.0.3), loo(v.2.8.0), farver(v.2.1.1), sass(v.0.4.9), utf8(v.1.2.3), labeling(v.0.4.3), ggplotify(v.0.1.2), tidyselect(v.1.2.1), rlang(v.1.1.0), munsell(v.0.5.1), tools(v.4.2.3), cachem(v.1.0.7), cli(v.3.6.1), pacman(v.0.5.1), generics(v.0.1.3), broom(v.1.0.4), evaluate(v.0.24.0), fastmap(v.1.1.1), ragg(v.1.2.5), yaml(v.2.3.7), processx(v.3.8.4), knitr(v.1.42), fs(v.1.6.4), tidygraph(v.1.3.0), nlme(v.3.1-162), formatR(v.1.14), aplot(v.0.2.3), compiler(v.4.2.3), bayesplot(v.1.11.1), rstudioapi(v.0.14), curl(v.5.2.1), tweenr(v.2.0.3), bslib(v.0.7.0), stringi(v.1.7.12), ps(v.1.7.7), highr(v.0.11), Brobdingnag(v.1.2-9), lattice(v.0.20-45), nloptr(v.2.1.1), tensorA(v.0.36.2.1), vctrs(v.0.6.1), pillar(v.1.9.0), lifecycle(v.1.0.4), jquerylib(v.0.1.4), bridgesampling(v.1.1-2), estimability(v.1.5.1), data.table(v.1.14.8), insight(v.0.20.1), patchwork(v.1.2.0), QuickJSR(v.1.3.0), R6(v.2.5.1), codetools(v.0.2-19), boot(v.1.3-28.1), MASS(v.7.3-58.2), assertthat(v.0.2.1), rprojroot(v.2.0.4), withr(v.3.0.0), multcomp(v.1.4-25), rlist(v.0.4.6.2), parallel(v.4.2.3), hms(v.1.1.3), grid(v.4.2.3), ggfun(v.0.1.5), coda(v.0.19-4.1), minqa(v.1.2.7), rmarkdown(v.2.21), TTR(v.0.24.4), ggforce(v.0.4.1) and numDeriv(v.2016.8-1.1)

LS0tDQp0aXRsZTogIkVJUEFBQl9kYXRhX3N1bW1hcnkiDQphdXRob3I6ICJKYWtlIE1hcnRpbiINCmRhdGU6ICJgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVkICVCICVZJylgIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBkZXB0aDogNA0KICAgIG51bWJlcl9zZWN0aW9uczogbm8NCiAgICB0aGVtZTogIGNvc21vDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZmxvYXQ6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICBwZGZfZG9jdW1lbnQ6DQogICAgdG9jOiB5ZXMNCmtuaXQ6IHwNCiAgKGZ1bmN0aW9uKGlucHV0LCAuLi4pIHsNCiAgICBybWFya2Rvd246OnJlbmRlcigNCiAgICAgIGlucHV0LA0KICAgICAgb3V0cHV0X2ZpbGUgPSBwYXN0ZTAoDQogICAgICAgJ2luZGV4Lmh0bWwnDQogICAgICApLA0KICAgICAgZW52aXIgPSBnbG9iYWxlbnYoKQ0KICAgICkNCiAgfSkNCi0tLQ0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZSA9IEZBTFNFfQ0KI2tuaXRlciBzZWV0dGluZw0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KA0KbWVzc2FnZSA9IEZBTFNFLA0Kd2FybmluZyA9IEZBTFNFLCAjIG5vIHdhcm5pbmdzDQpjYWNoZSA9IFRSVUUsIyBDYWNoZWluZyB0byBzYXZlIHRpbWUgd2hlbiBrbml0aW5nDQp0aWR5ID0gVFJVRQ0KKQ0KDQojIGNsZWFybmluZyB1cA0KI3JtKGxpc3Q9bHMoKSkNCmBgYA0KDQojIDEgUkVBRCBNRQ0KDQpJIHJlY29tbWVuZGVkIHlvdSByZWFkIHRoZSAnUkVBRE1FJyBmaWxlcyBiZWZvcmUgeW91IHdvcmsgd2l0aCB0aGUgRUlQQUFCIGRhdGFiYXNlLCB0aGVyZSBhcmUgdHdvICciJ1JFQURNRS5tZCcgYW5kICdSRUFETUUuY3N2Jywgc3RhcnQgd2l0aCB0aGUgJy5tZCcgZmlsZSAoaHR0cHM6Ly9naXRodWIuY29tL0pha2VNYXJ0aW5SZXNlYXJjaC9FSVBBQUItZGF0YWJhc2UvYmxvYi9tYWluL1JFQURNRS5tZCkNCg0KIyAyIFdlbG9jbWUNCg0KVGhpcyBpcyB0aGUgdGhlIFIgbWFya2Rvd24gc2NyaXB0IHdyaXR0ZW4gaW4gUiBzdHVkaW8gKDIwMjMuMDkuMCs0NjMgIkRlc2VydCBTdW5mbG93ZXIiIFJlbGVhc2UpIHVzZWQgdG8gc3VtbWFyaXNlIHRoZSBzeXN0ZW1hdGljIG1hcCBkYXRhYmFzZSBmcm9tIE1hcnRpbiBldCBhbC4gMjAyNCAiRXZpZGVuY2Ugb2YgdGhlIGltcGFjdHMgb2YgcGhhcm1hY2V1dGljYWxzIG9uIGFxdWF0aWMgIGFuaW1hbCBiZWhhdmlvdXIgKEVJUEFBQik6IGEgc3lzdGVtYXRpYyBtYXAgYW5kIG9wZW4gYWNjZXNzIGRhdGFiYXNlIiAoZG9pOiBYWFhYWCkuIA0KDQpJdCBpcyBkZXNpZ25lZCB0byBhY3QgYXMgYSBzdGFydGluZyBwb2ludCBmb3IgYW55b25lIHdobyB3aXNoZXMgdG8gdXNlIHRoZSAnRXZpZGVuY2Ugb2YgdGhlIEltcGFjdHMgb2YgUGhhcm1hY2V1dGljYWxzIG9uIEFxdWF0aWMgIEFuaW1hbCBCZWhhdmlvdXInIChFSVBBQUIpIGRhdGFiYXNlIGZvciB0aGVpciBvd24gcHJvamVjdHMuIA0KDQpUaGlzIHNjcmlwdCB3YXMgYXV0aG9yZWQgYnkgSmFrZSBNIE1hcnRpbiAoamFrZW1hcnRpbi5vcmcpDQoNCkNvbnRhY3Q6IGpha2UubWFydGluQGRlYWtpbi5lZHUgb3IgamFrZS5tYXJ0aW5Ac2x1LnNlDQoqUC5zIEFwb2xvZ2llcyBmb3IgYW55IHNwZWxsaW5nIG1pc3Rha2VzIGluIHRoZSBzY3JpcHQgSSBhbSBkeXNsZXhpYyBhbmQgdGhpcyBpcyBhIHZlcnkgbG9uZyBkb2N1bWVudCANCg0KIyAzIFIgaW5mb3JtYXJ0aW9uDQoNCklmIHlvdSBhcmUgbm90IGZhbWlsaWFyIHdpdGggUiwgaGVyZSdzIGEgYmVnaW5uZXJzIGd1aWRlIChodHRwczovL3d3dy55b3V0dWJlLmNvbS93YXRjaD92PV9WOGVLc3RvM1VnKS4gDQoNCkhlcmUncyBhIGxpbmsgdG8gZG93bmxvYWQgUiAoaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvKSBhbmQgUiBzdHVkaW8gKGh0dHBzOi8vcG9zaXQuY28vcHJvZHVjdHMvb3Blbi1zb3VyY2UvcnN0dWRpby8pLCBhbmQgYSBndWlkZSBvbiBob3cgdG8gZG8gc28uDQoNClRoaXMgaXMgYW4gUiBtYXJrZG93biBmaWxlLCB3aGljaCBtYWtlcyBhbm5vdGF0aW5nIGFuZCBydW5uaW5nIFIgY29kZSBtb3JlIHVzZXIgZnJpZW5kbHksIGl0IGlzIGFsc28gZWFzeSB0byByZXByb2R1Y2libGUgYW5kIHNoYXJlIGluIGEgdmFyaWF0ZSBvZiBmb3JtYXRlcyAoZS5nLiBQREYpLiBUaGUgUiBjb2RlIGlzIGVtYmVkIHdpdGhpbiBjaHVua3MsIGFuZCB0aGUgb3V0cHV0IGZvciBjb2RlIHdpbGwgYmUgZW1iZWRkZWQgdW5kZXIgdGhlIGNodWNrLg0KDQpgYGB7cn0gDQojIFRoaXMgaXMgYSBjaHVjaw0KYGBgDQoNCkFsbCBvdGhlciB0ZXh0IG91dHNpZGUgb2YgdGhlIGNodWNrcyBhcmUgYW5ub3RhdGlvbnMgKGxpa2UgdGhpcykuIEhhc2h0YWdzIHVzZWQgb3V0c2lkZSBvZiBjaHVja3MgYXJlIHVzZWQgdG8gY3JlYXRlIGhlYWRlcnMgYW5kIHRvIHN0cnVjdHVyZSB0aGUgZmlsZS4gSGFzaHRhZ3Mgd2l0aGluIHRoZSBjaHVja3MgYXJlIHVzZWQgZm9yIG1vcmUgcHJlY2lzZSBhbm5vdGF0aW9uIHdpdGhpbiB0aGUgY29kZS4NCg0KSWYgeW91IGFyZSBub3QgZmFtaWxpYXIgd2l0aCBSIG1hcmtkb3duLCBoZXJlJ3MgYSBndWlkZSAoaHR0cHM6Ly93d3cueW91dHViZS5jb20vd2F0Y2g/dj10S1V1Znpwb0hERSkNCg0KIyA0IFJlcXVpcmVkIFIgcGFja2FnZXMNCg0KVGhlc2UgYXJlIHRoZSBSIHBhY2thZ2VzIHJlcXVpcmVkIHRvIHJ1biB0aGUgc2NyaXB0LiBJIGhhdmUgYWRkZWQgdGhlbSB0byBhIGxpc3Qgc28gdGhhdCBJIGNhbiBpbnN0YWxsIHRoZW0gYWxsIGluIG9uZSBnbyB1c2luZyB0aGUgZnVuY3Rpb24gYmVsb3cgY2FsbGVkIGxvYWRlZF9wYWNrYWdlcy4gVGhpcyBmdW5jdGlvbiBJIGhhdmUgbWFkZSB3aWxsIGxvYWQgYWxsIHRoZSBwYWNrYWdlcyBpbiB0aGUgbGlzdCBiZWxvdywgaWYgdGhlIHBhY2thZ2VzIGFyZSBub3QgYWxyZWFkeSBpbnN0YWxsZWQsIHRoaXMgZnVuY3Rpb24gd2lsbCBmaXJzdCBpbnN0YWxsIHRoZW0uDQoNCklmIHlvdSB3YW50IHRvIGluc3RhbGwgYW5kIGxvYWQgZWFjaCBwYWNrYWdlIHNlcGFyYXRlbHksIHlvdSBjYW4gdXNlIHRoZSBjb2RlIGluc3RhbGwucGFja2FnZXMoKSBhbmQgcmVxdWlyZSgpLCBJIGhhdmUgZ2l2ZW4gYSBleGFtcGxlIGJlbG93Lg0KDQpgYGB7cn0NCiMgdGhpcyBpbnN0YWxscyBhbmQgbG9hZCBwYWNrYWdlcw0KIyBuZWVkIHRvIGluc3RhbGwgcGFjbWFuDQpwYWNtYW46OnBfbG9hZCgidGlkeXZlcnNlIiwgDQogICAgICAgICAgICAgICAgICAgICAgICJnZ3JhcGgiLCANCiAgICAgICAgICAgICAgICAgICAgICAgImlncmFwaCIsIA0KICAgICAgICAgICAgICAgICAgICAgICAiZ2dyZXBlbCIsIA0KICAgICAgICAgICAgICAgICAgICAgICAiUkNvbG9yQnJld2VyIiwNCiAgICAgICAgICAgICAgICAgICAgICAgImdndHJlZSIsDQogICAgICAgICAgICAgICAgICAgICAgICJ0cmVlaW8iLA0KICAgICAgICAgICAgICAgICAgICAgICAiYXBlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgImdyaWRFeHRyYSIsDQogICAgICAgICAgICAgICAgICAgICAgICJnZ2Rpc3QiLA0KICAgICAgICAgICAgICAgICAgICAgICAiaGlnaGNoYXJ0ZXIiLA0KICAgICAgICAgICAgICAgICAgICAgICAicGFuZGVyIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICJoZXJlIg0KICAgICAgICAgICAgICAgICAgICAgICApDQpgYGANCg0KDQpGb3IgZ2d0cmVlIGFuZCB0cmVlaW8geW91IG1heSBuZWVkIHRvIHJ1biB0aGlzIGNvZGUgZm9yIGluc3RpbGxhdGlvbiANCg0KYGBge3J9DQojIGlmICghcmVxdWlyZU5hbWVzcGFjZSgiQmlvY01hbmFnZXIiLCBxdWlldGx5ID0gVFJVRSkpDQojICAgICBpbnN0YWxsLnBhY2thZ2VzKCJCaW9jTWFuYWdlciIpDQojIA0KIyBCaW9jTWFuYWdlcjo6aW5zdGFsbCgiZ2d0cmVlIikNCmBgYA0KDQojIDUgRGlyZWN0b3JpZXMNCg0KQ3JlYXRpbmcgb3V0IGlucHV0IGFuZCBvdXRwdXQgZGlyZWN0b3JpZXMuIFRoZXkgd2lsbCBiZSBtYWRlIHdpdGhpbiB0aGUgY3VycmVudCBwYXJlbnQgZGlyZWN0b3J5IChpLmUuIHdoZXJlIHRoZSBSIHNjaXBydCBpcyBzYXZlZCkNCg0KVGhpcyBpcyBjb2RlIGNyZWF0ZXMgYSBmb2xkZXIgYW5kIHNhdmVzIHRoZSBkaXJlY3RvcnkgYXMgZmlndXJlX3BhdGguIFRoaXMgaXMgd2hlcmUgd2Ugd2lsbCBleHBvcnQgb3VyIGZpZ3VyZXMNCg0KYGBge3J9DQpmaWd1cmVzX3BhdGggPC0gaGVyZSgiZmlndXJlcyIpDQoNCmlmICghZGlyLmV4aXN0cyhmaWd1cmVzX3BhdGgpKSB7DQogIGRpci5jcmVhdGUoZmlndXJlc19wYXRoKQ0KfQ0KYGBgDQoNClRoaXMgaXMgY29kZSBjcmVhdGVzIGEgZm9sZGVyIGFuZCBzYXZlcyB0aGUgZGlyZWN0b3J5IGFzIG91dHB1dF9wYXRoIFRoaXMgaXMgd2hlcmUgd2Ugd2lsbCBleHBvcnQgb3VyIGRhdGENCg0KYGBge3J9DQpvdXRwdXRfcGF0aCA8LSBoZXJlKCJvdXRwdXQtZGF0YSIpDQoNCmlmICghZGlyLmV4aXN0cyhvdXRwdXRfcGF0aCkpIHsNCiAgZGlyLmNyZWF0ZShvdXRwdXRfcGF0aCkNCn0NCmBgYA0KDQpJbnB1dCBkaXJlY3RvcnkgDQoNCmBgYHtyfQ0KaW5wdXRfcGF0aCA8LSBoZXJlKCJpbnB1dC1kYXRhIikNCg0KaWYgKCFkaXIuZXhpc3RzKGZpZ3VyZXNfcGF0aCkpIHsNCiAgZGlyLmNyZWF0ZShmaWd1cmVzX3BhdGgpDQp9DQpgYGANCg0KIyA2IERhdGFiYXNlIGluZm9ybWFydGlvbg0KDQpUaGUgJ0V2aWRlbmNlIG9mIHRoZSBJbXBhY3RzIG9mIFBoYXJtYWNldXRpY2FscyBvbiBBcXVhdGljICBBbmltYWwgQmVoYXZpb3VyJyAoRUlQQUFCKSBkYXRhYmFzZSBoYXMgOTYgY29sdW1ucyBhbmQgMTc1NCByb3dzLiBUaGUgY29sdW1ucyByZXByZXNlbnQgdmFyaW91cyBmb3JtcyBvZiBtZXRhZGF0YSBleHRyYWN0ZWQgZnJvbSBhcnRpY2xlcyB0aGF0IHdlcmUgaW5jbHVkZWQgaW4gTWFydGluIGV0IGFsLiAyMDI0ICJFdmlkZW5jZSBvZiB0aGUgaW1wYWN0cyBvZiBwaGFybWFjZXV0aWNhbHMgb24gYXF1YXRpYyAgYW5pbWFsIGJlaGF2aW91cjogYSBzeXN0ZW1hdGljIG1hcCBhbmQgb3BlbiBhY2Nlc3MgZGF0YWJhc2UiIChkb2k6IFhYWFhYKS4NCg0KVGhlIFJFQUQtTUUgZmlsZSB3aGljaCBleHBsYWlucyB3aGF0IGVhY2ggbWV0YWRhdGEgaXMsIGhvdyBpdCB3YXMgZXh0cmFjdGVkLCB3aGF0IHN0cnVjdHVyZSBpdCBoYXMsIGFuZCBhdCB3aGF0IGxldmVsIGl0IGFwcGxpZXMsIGlzIGF2YWlsYWJsZSBhdCBYWFguIEJlbG93IEkgaGF2ZSBpbXBvcnRlZCB0aGUgcmVhZCBtZSBmb3IgYWNjZXNzaWJpbGl0eS4gSSBoaWdobHkgcmVjb21tZW5kIHlvdSByZWFkIHRoZSBSRUFELU1FIGJlZm9yZSBjb25kdWN0aW5nIGFueSBvZiB5b3VyIG93biBtZXRhLWFuYWx5c2lzIHRvIG1ha2Ugc3VyZSB5b3UgaGF2ZSBpbnRlcm9wZXJhdGVkIHRoZSBkYXRhIGNvcnJlY3RseS4gIA0KDQpNb3JlIGdlbmVyYWxseSwgY29sdW1uIG5hbWVzIHRoYXQgc3RhcnQgd2l0aCAndmFsaWRpdHknIGFyZSBtZXRhZGF0YSByZWxhdGluZyB0byBzdHVkeSB2YWxpZGl0eSwgdGhvc2UgdGhhdCBzdGFydCB3aXRoICdzcGVjaWUncyByZWxhdGUgdG8gc3BlY2llcyBpbmZvcm1hdGlvbiAocG9wdWxhdGlvbiksIHRob3NlIHRoYXQgc3RhcnQgd2l0aCAnY29tcG91bmQnIHJlbGF0ZSB0byB0aGUgY2hlbWljYWwgaW5mb3JtYXRpb24gKGV4cG9zdXJlKSwgdGhvc2UgdGhhdCBzdGFydCB3aXRoICdiZWhhdicgcmVsYXRlIHRvIGJlaGF2aW91ciBpbmZvcm1hdGlvbiAob3V0Y29tZSkuIFRoZSBvcmRlciBvZiBjb2x1bW5zIHJlZmxlY3RzIGJvdGggdGhlIGxldmVsIHRoZSBtZXRhZGF0YSBpcyBleHRyYWN0ZWQgYXQgKGkuZS4gYXJ0aWNsZSBsZXZlbCBvciBzcGVjaWVzIGJ5IGNvbXBvdW5kIGxldmVsOyBzZWUgbGV2ZWwgaW4gUkVBRC1NRSksIGFzIHdlbGwgYXMgdGhlIGdlbmVyYWwgY2F0ZWdvcnkgb2YgbWV0YWRhdGEgKGkuZS4gdmFsaWRpdHksIHNwZWNpZXMsIGNvbXBvdW5kLCBiZWhhdmlvdXIpLg0KDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCnNldHdkKGlucHV0X3BhdGgpDQoNClJFQURfTUUgPC0gcmVhZC5jc3YoIlJFQUQtTUUuY3N2IiwgbmEgPSAiTkEiKSAjIGxvYWRpbmcgdGhlIFJFQUQtTUUgZmlsZQ0KYGBgDQoNCg0KIyA3IEltcG9ydGluZyBFSVBBQUIgZGF0YWJhc2UNCg0KSW1wb3J0aW5nIHRoZSBFSVBBQUItZGF0YWJhc2UuY3N2IGRhdGFiYXNlIChhY2Nlc3NlZCBmcm9tOiBodHRwczovL29zZi5pby9hdHd5Ni8pLg0KDQpJZiB0aGUgQ1NWIGZpbGVzIGFyZSBpbiB0aGUgc2FtZSB3b3JraW5nIGRpcmVjdG9yeSAod2QpIGFzIHRoaXMgUiBzY3JpcHQsIHlvdSB3aWxsIG5vdCBuZWVkIHRvIHVzZSBzZXR3ZCgpLCBidXQgaWYgdGhlIGZpbGVzIGFyZSBsb2NhdGVkIGVsc2V3aGVyZSB5b3Ugd2lsbCBuZWVkIHRvIHNwZWNpZnkgdGhpcyBpbiBzZXR3ZCgpLCBhbmQgcnVuIGFsbCBsaW5lcyBhdCBvbmNlLiBJbiBSIG1hcmtkb3duIHRoZSB3b3JraW5nIGRpcmVjdG9yeSBjaGFuZ2VzIGJhY2sgdG8gZGVmYXVsdCBhZnRlciB0aGUgY2h1Y2sgaXMgcnVuLg0KDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCnNldHdkKGlucHV0X3BhdGgpDQoNCkVJUEFBQl9kYXRhYmFzZSA8LSByZWFkLmNzdigiRUlQQUFCLWRhdGFiYXNlLmNzdiIsIG5hID0gIk5BIikNCmBgYA0KDQoNCiMgOCBUb3RhbCBudW1iZXJzDQoNClRoZSBmaXJzdCB0aGluZyB3ZSB3aWxsIGxvb2sgYXQgaXMgaG93IG1hbnkgdW5pcXVlIChkaXN0aW5jdCkgYXJ0aWNsZXMgdGhlcmUgYXJlIGluIHRoZSBkYXRhYmFzZSwgYW5kIGhvdyBtYW55IHJvd3Mgb2YgZGF0YSB0aGVyZSBhcmUuDQoNClRoZXJlIGFyZSA5MDEgYXJ0aWNsZXMsIHdpdGggMTc0MCByb3dzLg0KDQpgYGB7cn0NCkVJUEFBQl9kYXRhYmFzZSAlPiUgIA0KICBkcGx5cjo6ZGlzdGluY3QoYXJ0aWNsZV9pZCkgJT4lICMgUmV0dXJucyBhIGxpc3Qgb2YgZGlzdGluY3QgYXJ0aWNsZV9pZA0KICBucm93KC4pICMgUmV0dXJucyB0aGUgbGVuZ3RoIG9mIHRoZSBjdXJyZW50IGZpbGUgKHdoaWNoIGlzIHRoZSBsaXN0IG9mIGRpc3RpbmN0IGFydGljbGVfaWQpDQoNCkVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIG5yb3coLikgIyBSZXR1cm5zIHRoZSBsZW5ndGggb2YgdGhlIGN1cnJlbnQgZmlsZSAod2hpY2ggaXMgdGhlIGxlbmd0aCBvZiB0aGUgd2hvbGUgZGF0YWZpbGUpDQpgYGANCg0KRWFjaCByb3cgcmVwcmVzZW50IGEgdW5pcXVlIHNwZWNpZXMgYnkgY29tcG91bmQgY29tYmluYXRpb24gd2l0aGluIGEgZ2l2ZW4gYXJ0aWNsZS4gVGhpcyBpcyByZXByZXNlbnRlZCBieSB0aGUgY29sdW1uIHVuaXF1ZV9yb3dfaWQgVGhpcyBpcyBhIGNvbWJpbmF0aW9uIG9mIHRoZSBleHRyYWN0b3JzIHJlc3BvbnNlIGlkLCBzcGVjaWUscyBhbmQgY29tcG91bmQuIEZvciBleGFtcGxlLCBSXzBCcXoyUlE0SnhQZkJrWl9EYW5pb19yZXJpb19EaWF6ZXBhbSwgcmVzcG9uc2UgaWQgPSBSXzBCcXoyUlE0SnhQZkJrWiwgc3BlY2llcyA9IERhbmlvIHJlcmlvLCBhbmQgY29tcG91bmQgPSBEaWF6ZXBhbQ0KDQpgYGB7cn0NCkVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIGRwbHlyOjpzZWxlY3QodW5pcXVlX3Jvd19pZCkgJT4lICMgc2VsZWN0cyBqdXN0IHRoZSB1bmlxdWVfY29sdW1uX2lkIGNvbHVtbg0KICBkcGx5cjo6YXJyYW5nZSh1bmlxdWVfcm93X2lkKSAlPiUgIyBhcnJhbmdlcyB0aGUgY29sdW1uIGFscGhhYmV0aWNhbGx5IHNvIHRoZSBzYW1lIGV4YW1wbGVzIHdpbGwgYmUgZ2l2ZW4gZXZlcnl0aW1lIA0KICBkcGx5cjo6c2xpY2UoMToxMCkgIyBSZXR1cm5zIG9ubHkgdGhlIGZpcnN0IDEwIHJvd3MNCmBgYA0KDQpOb3cgdGhlIG51bWJlciBvZiB0b3RhbCB0cmVhdG1lbnRzIHJlcHJlc2VudGVkIGluIHRoZSBkYXRhLCB0aGlzIGlzIHRoZSB0b3RhbCBudW1iZXIgb2YgdW5pcXVlIGRvc2VzIHBlciBzcGVjaWVzIGJ5IGNvbXBvdW5kIGNvbWJpbmF0aW9uLg0KDQpJbiB0aGUgbWFwIHRoZSBudW1iZXIgb2YgdHJlYXRtZW50cyB3YXMgb25seSBleHRyYWN0ZWQgZm9yIHdhdGVyLWJvcm5lIGV4cG9zdXJlcywgdGhlIE5BcywgcmVwcmVzZW50IG90aGVyIGV4cG9zdXJlIHJvdXRlcy4gVGhlcmVmb3JlLCB0aGUgbnVtYmVyIG9mIHdhdGVyLWJvcm5lIGV4cG9zdXJlcyB0cmVhdG1lbnRzIGFyZSA2Mjk0LCBhbmQgdGhlcmUgYXJlIGFuIGFkZGl0aW9uYWwgMjI2IGFydGljbGVzIHRoYXQgZG9uJ3QgaGF2ZSB0cmVhdG1lbnQgbnVtYmVycy4gV2Uga25vdyB0aGV5IGFsbCBoYXZlIGF0IGxlYXN0IHR3byB0cmVhdG1lbnRzLCBhIGNvbnRyb2wgYW5kIGEgY29tcG91bmQgb2YgaW50ZXJlc3QsIGJlY2F1c2UgdGhhdCBpcyBwYXJ0IG9mIHRoZSBpbmNsdXNpb24gY3JpdGVyaWEuIFNvIHdlIGNvdWxkIGFkZCB0aGUgbnVtYmVyIG9mIE5BcyAqIDIgdG8gdGhlIHRvdGFsLCB0aGlzIHdvdWxkIGJlIDY3NDYgdG90YWwgdHJlYXRtZW50IGdyb3Vwcy4gQWx0aG91Z2gsIHRoaXMgd291bGQgbGlrZWx5IGJlIGFuIHVuZGVyZXN0aW1hdGUgb2YgdGhlIHRydWUgdG90YWwuDQoNCmBgYHtyfQ0KRUlQQUFCX2RhdGFiYXNlICU+JSANCiAgZHBseXI6OnN1bW1hcmlzZSgNCiAgICBncm91cHMgPSBzdW0oY29tcG91bmRfdHJlYXRtZW50X2xldmVscywgbmEucm0gPSBUUlVFKSwgIyBDYWxjdWxhdGUgdGhlIHN1bSBvZiAnY29tcG91bmRfdHJlYXRtZW50X2xldmVscycgd2hpbGUgaWdub3JpbmcgTkEgdmFsdWVzDQogICAgbmFzID0gc3VtKGlzLm5hKGNvbXBvdW5kX3RyZWF0bWVudF9sZXZlbHMpKSwgIyBDb3VudCB0aGUgbnVtYmVyIG9mIE5BIHZhbHVlcyBpbiAnY29tcG91bmRfdHJlYXRtZW50X2xldmVscycNCiAgICB0b3RhbCA9IGdyb3VwcyArIChuYXMgKiAyKSAjIENhbGN1bGF0ZSB0aGUgdG90YWwgYnkgYWRkaW5nICdncm91cHMnIHRvIHR3aWNlIHRoZSBudW1iZXIgb2YgTkFzDQogICkNCmBgYA0KDQojIDkgU3R1ZHkgbW90aXZhdGlvbg0KDQpMZXQncyBsb29rIGF0IGhvdyB0aGUgZXZpZGVuY2UgY29sbGVjdGVkIGJyZWFrcyBkb3duIGJ5IHRoZSB0aHJlZSBzdHVkeSBtb3RpdmF0aW9ucw0KDQpgYGB7cn0NCnRvdGFsX2F0cmljbGVzIDwtIEVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIGRwbHlyOjpkaXN0aW5jdChhcnRpY2xlX2lkKSAlPiUgDQogIG5yb3coKQ0KDQojIEFuYWx5emUgdGhlIHN0dWR5IG1vdGl2YXRpb25zIGluIHRoZSBkYXRhc2V0DQpFSVBBQUJfZGF0YWJhc2UgJT4lDQogIGRwbHlyOjpncm91cF9ieShhcnRpY2xlX2lkKSAlPiUgIyBHcm91cCB0aGUgZGF0YSBieSAnYXJ0aWNsZV9pZCcNCiAgZHBseXI6OnNhbXBsZV9uKDEpICU+JSAjIFJhbmRvbWx5IHNhbXBsZSBvbmUgcm93IGZyb20gZWFjaCBncm91cCAoaS5lLiwgZWFjaCB1bmlxdWUgJ2FydGljbGVfaWQnKQ0KICBkcGx5cjo6dW5ncm91cCgpICU+JSAjIFVuZ3JvdXAgdGhlIGRhdGEgdG8gcmVtb3ZlIHRoZSBwcmV2aW91cyBncm91cGluZw0KICBkcGx5cjo6Z3JvdXBfYnkoc3R1ZHlfbW90aXZhdGlvbikgJT4lICMgR3JvdXAgdGhlIGRhdGEgYnkgJ3N0dWR5X21vdGl2YXRpb24nDQogIGRwbHlyOjpyZWZyYW1lKCAjIENyZWF0ZSBhIHN1bW1hcnkgZGF0YSBmcmFtZSB3aXRoIHRoZSBjb3VudCBhbmQgcGVyY2VudGFnZSBvZiBlYWNoIHN0dWR5IG1vdGl2YXRpb24NCiAgICBuID0gbGVuZ3RoKHN0dWR5X21vdGl2YXRpb24pLCAgIyBDb3VudCB0aGUgbnVtYmVyIG9mIG9jY3VycmVuY2VzIG9mIGVhY2ggc3R1ZHkgbW90aXZhdGlvbg0KICAgIGAlYCA9IHJvdW5kKG4gLyB0b3RhbF9hdHJpY2xlcywgMykgKiAxMDAgICMgQ2FsY3VsYXRlIHRoZSBwZXJjZW50YWdlIG9mIHRvdGFsIGFydGljbGVzDQogICkgJT4lIA0KICBkcGx5cjo6YXJyYW5nZShkZXNjKG4pKSAjIEFycmFuZ2UgdGhlIHJlc3VsdGluZyBkYXRhIGZyYW1lIGluIGRlc2NlbmRpbmcgb3JkZXIgb2YgdGhlIGNvdW50DQpgYGANCg0KSGVyZSB3ZSBhcmUgY2hhbmdpbmcgdGhlIG9yZGVyIG9mIHRoZXNlIGluIHRoZSBkYXRhYmFzZSB0byAiRW52aXJvbm1lbnRhbCIsICJNZWRpY2FsIiwgIkJhc2ljIHJlc2VhcmNoIiBmb3IgcGxvdHMuDQoNCmBgYHtyfQ0KRUlQQUFCX2RhdGFiYXNlIDwtIEVJUEFBQl9kYXRhYmFzZSAlPiUNCiAgZHBseXI6Om11dGF0ZShzdHVkeV9tb3RpdmF0aW9uID0gZmN0X3JlbGV2ZWwoc3R1ZHlfbW90aXZhdGlvbiwgIkVudmlyb25tZW50YWwiLCAiTWVkaWNhbCIsICJCYXNpYyByZXNlYXJjaCIpKQ0KYGBgDQoNCiMgMTAgUHVibGljYXRpb25zIGJ5IHllYXINCg0KIyMgMTAuMSBOdW1iZXIgcGVyIHllYXINCg0KWWVhciByYW5nZSBpcyAxOTc0IHRvIDIwMjIsIHNvIDQ4IHllYXJzIHdvcnRoIG9mIGVtcGlyaWNhbCByZXNlYXJjaCBoYXMgY29udHJpYnV0ZWQgdG8gdGhpcyBldmlkZW5jZSBiYXNlLg0KDQpgYGB7cn0NCkVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG1pbl95ZWFyID0gbWluKHllYXIpLA0KICAgICAgICAgICAgICAgICBtYXhfeWVhciA9IG1heCh5ZWFyKSwNCiAgICAgICAgICAgICAgICAgdG90YWxfeWVhcnMgPSBtYXhfeWVhci1taW5feWVhcikNCmBgYA0KDQpOb3cgbWFraW5nIGEgc3VtbWFyeSBmb3IgdGhlIG51bWJlciBvZiBwdWJsaWNhdGlvbnMgcGVyIHllYXIgYmFzZWQgb24gc3R1ZHkgbW90aXZhdGlvbg0KDQpgYGB7cn0NCiMgQ3JlYXRlIGEgY29tcGxldGUgc2VxdWVuY2Ugb2YgeWVhcnMgYW5kIGFsbCB1bmlxdWUgc3R1ZHkgbW90aXZhdGlvbnMNCmFsbF95ZWFycyA8LSBhcy5jaGFyYWN0ZXIoMTk3NDoyMDIyKQ0KYWxsX3N0dWR5X21vdGl2YXRpb25zIDwtIHVuaXF1ZShFSVBBQUJfZGF0YWJhc2Ukc3R1ZHlfbW90aXZhdGlvbikNCg0KIyBDcmVhdGUgYSBkYXRhIGZyYW1lIHdpdGggYWxsIGNvbWJpbmF0aW9ucyBvZiB5ZWFyIGFuZCBzdHVkeSBtb3RpdmF0aW9uDQphbGxfY29tYmluYXRpb25zIDwtIGV4cGFuZC5ncmlkKHllYXIgPSBhbGxfeWVhcnMsIHN0dWR5X21vdGl2YXRpb24gPSBhbGxfc3R1ZHlfbW90aXZhdGlvbnMsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkNCg0KIyBTdW1tYXJpemUgdGhlIGRhdGENCnB1Yl95ZWFyIDwtIEVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIGdyb3VwX2J5KHllYXIsIHN0dWR5X21vdGl2YXRpb24pICU+JSANCiAgc3VtbWFyaXplKG4gPSBsZW5ndGgodW5pcXVlKGFydGljbGVfaWQpKSwgLmdyb3VwcyA9ICdkcm9wJykgJT4lIA0KICBtdXRhdGUoeWVhciA9IGFzLmNoYXJhY3Rlcih5ZWFyKSkNCg0KIyBKb2luIHdpdGggdGhlIGNvbXBsZXRlIGdyaWQgb2YgeWVhcnMgYW5kIHN0dWR5IG1vdGl2YXRpb25zDQpwdWJfeWVhcl9jb21wbGV0ZSA8LSBhbGxfY29tYmluYXRpb25zICU+JQ0KICBsZWZ0X2pvaW4ocHViX3llYXIsIGJ5ID0gYygieWVhciIsICJzdHVkeV9tb3RpdmF0aW9uIikpICU+JQ0KICBtdXRhdGUobiA9IGlmX2Vsc2UoaXMubmEobiksIDAsIG4pLA0KICAgICAgICAgeWVhciA9IGFzLm51bWVyaWMoeWVhcikpDQpgYGANCg0KSGVyZSdzIGEgc3VtbWFyeSBmaWd1cmUgZm9yIHRoZSBtYW51c2NyaXB0IChNUykuIA0KDQpgYGB7cn0NCiMgRGVmaW5lIHRoZSBjb2xvdXIgcGFsZXR0ZQ0KbW90aXZhdGlvbl9jb2xvdXJfdGhlbWUgPC0gYygiIzYwQkQ2QyIsICIjRDM1OUExIiwgIiMzQzgyQzQiKSAjIE1ha2luZyBjb2xvdXIgdGhlbWUgdG8gYXBwbHkgdG8gcGxvdA0KDQojIENyZWF0ZSB0aGUgcGxvdA0KcHViX3llYXJfZmlnIDwtIHB1Yl95ZWFyX2NvbXBsZXRlICU+JQ0KICAjIEdyb3VwIHllYXJzIGJlZm9yZSAxOTk2IGFuZCByZWZvcm1hdCB0aGUgeWVhciBjb2x1bW4NCiAgZHBseXI6Om11dGF0ZSgNCiAgICB5ZWFyID0gYXMuY2hhcmFjdGVyKGlmX2Vsc2UoeWVhciA8IDE5OTYsIDE5OTYsIHllYXIpKSwgIyBHcm91cGluZyB5ZWFycyBiZWZvcmUgMTk5Ng0KICAgIHllYXIgPSBpZl9lbHNlKHllYXIgPT0gIjE5OTYiLCAiPDE5OTciLCB5ZWFyKSAgICAgICAgICAjIFJlbmFtaW5nIDE5OTUgZ3JvdXAgdG8gIjwxOTk2Ig0KICApICU+JQ0KICAjIENyZWF0aW5nIHRoZSBwbG90DQogIGdncGxvdChhZXMoeSA9IG4sIHggPSB5ZWFyLCBmaWxsID0gc3R1ZHlfbW90aXZhdGlvbikpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHdpZHRoID0gMC45KSArDQogICMgQXBwbHkgdGhlIGN1c3RvbSBjb2xvdXJzDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IG1vdGl2YXRpb25fY29sb3VyX3RoZW1lLCBuYW1lID0gIlN0dWR5IG1vdGl2YXRpb24iKSArIA0KICB0aGVtZV9jbGFzc2ljKCkgKw0KICAjIEN1c3RvbWl6aW5nIHRoZSB0aGVtZQ0KICB0aGVtZSgNCiAgICBsZWdlbmQucG9zaXRpb24gPSBjKDAuMDUsIDEpLCAjIFBvc2l0aW9uaW5nIHRoZSBsZWdlbmQgaW4gdGhlIHRvcC1sZWZ0IGNvcm5lciB3aXRoaW4gdGhlIHBsb3QNCiAgICBsZWdlbmQuanVzdGlmaWNhdGlvbiA9IGMoMCwgMSksICMgRW5zdXJpbmcgdGhlIGxlZ2VuZCBib3ggYWxpZ25zIHByb3Blcmx5IGF0IHRoZSB0b3AtbGVmdCBjb3JuZXINCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSkgIyBSb3RhdGluZyB4LWF4aXMgbGFiZWxzIGZvciBiZXR0ZXIgcmVhZGFiaWxpdHkNCiAgKSArDQogICMgQWRkaW5nIGF4aXMgbGFiZWxzDQogIGxhYnMoDQogICAgeCA9ICJZZWFyIG9mIHB1YmxpY2F0aW9uIiwNCiAgICB5ID0gIk51bWJlciBvZiBhcnRpY2xlcyINCiAgKQ0KDQojIERpc3BsYXkgdGhlIHBsb3QNCnB1Yl95ZWFyX2ZpZw0KYGBgDQoNClNhdmluZyB0aGUgZmlndXJlIGFzIGEgUERGDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQ0Kc2V0d2QoZmlndXJlc19wYXRoKQ0KI2dnc2F2ZSgicHViX3llYXJfZmlnLnBuZyIsIHBsb3QgPSBwdWJfeWVhcl9maWcsIHdpZHRoID0gMTAsIGhlaWdodCA9IDUsIGRwaSA9IDMwMCkgI2lmIHlvdSB3YW50IHRvIHNhdmUgYSBwbmcNCmdnc2F2ZSgic3R1ZHlfcHViX3llYXJfZmlnLnBkZiIsIHBsb3QgPSBwdWJfeWVhcl9maWcsIHdpZHRoID0gMTAsIGhlaWdodCA9IDUpDQpgYGANCg0KIyMgMTAuMiBDdW11bGF0aXZlIGFuZCByZWxhdGl2ZSBncm93dGgNCg0KTWFraW5nIHZhbHVlcyBmb3IgY3VtdWxhdGl2ZSBhbmQgcmVsYXRpdmUgZ3Jvd3RoIGluIGFydGljbGVzLiBUaGlzIGlzIHRoZSBjdW11bGF0aXZlIG51bWJlciBvZiBhcnRpY2xlcyBwZXIgeWVhciBmb3IgZWFjaCBzdHVkeSBtb2l0dmF0aW9uLCBhcyB3ZWxsIGFzIHRoZSByZWxhdGl2ZSBncm93dGggYmFzZWQgb24gMjAwNy4gV2Ugc2VsZWN0ZWQgMjAwNyBmb3IgYSAxNSB5ZWFyIG92ZXJ2aWV3IGluIGdyb3d0aC4NCg0KYGBge3J9DQpwdWJfeWVhcl9ncm93dGggPC0gcHViX3llYXJfY29tcGxldGUgJT4lDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uKSAlPiUNCiAgZHBseXI6Om11dGF0ZSgNCiAgICBuX2N1bXVsYXRpdmUgPSBjdW1zdW0obiksICAjIENhbGN1bGF0ZSB0aGUgY3VtdWxhdGl2ZSBzdW0gb2YgJ24nDQogICAgbl9jdW11bGF0aXZlX3Byb3AgPSBuX2N1bXVsYXRpdmUgLyBtYXgobl9jdW11bGF0aXZlKSwgIyBDYWxjdWxhdGUgdGhlIGN1bXVsYXRpdmUgcHJvcG9ydGlvbg0KICAgIG5fMjAwNyA9IGlmZWxzZSh5ZWFyID09IDIwMDcsIG4sIE5BX3JlYWxfKSwgIyBHZXQgbiB2YWx1ZSBmb3IgeWVhciAyMDA3DQogICAgbl8yMDA3ID0gZmlyc3QobmEub21pdChuXzIwMDcpKSwgIyBQcm9wYWdhdGUgdGhlIG5fMjAxMiB2YWx1ZSB3aXRoaW4gdGhlIGdyb3VwDQogICAgbl9yYXRpb190b18yMDA3ID0gbiAvIG5fMjAwNyAjIENhbGN1bGF0ZSBudW1iZXIgb2YgYXJ0aWNsZXMgcmVsYXRpdmUgdG8gdGhhdCBvZiAyMDA3DQogICkgJT4lDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lDQogIGRwbHlyOjpzZWxlY3Qoc3R1ZHlfbW90aXZhdGlvbiwgeWVhciwgbiwgbl9jdW11bGF0aXZlLCBuX2N1bXVsYXRpdmVfcHJvcCwgbl9yYXRpb190b18yMDA3KQ0KYGBgDQoNCk1ha2luZyBhIHBsb3QgZm9yIGVhY2ggbW90aXZhdGlvbiBjdW11bGF0aXZlIGdyb3d0aCBzaW5jZSAxOTc0ICh0aGUgZmlyc3QgaWRlbnRpZmllZCBzdHVkeSkNCg0KYGBge3J9DQpjdW11bGF0aXZlX2FydGljbGVzX2ZpZyA8LSBwdWJfeWVhcl9ncm93dGggJT4lIA0KICBnZ3Bsb3QoYWVzKHkgPSBuX2N1bXVsYXRpdmUsIHggPSB5ZWFyLCBjb2xvdXIgPSBzdHVkeV9tb3RpdmF0aW9uKSkgKw0KICBnZW9tX2xpbmUoc3RhdCA9ICJpZGVudGl0eSIsIGxpbmV3aWR0aCA9IDEuNSkgKw0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKSArDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMTk3NCwgMjAyMiwgYnkgPSAxKSkgKw0KICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IG1vdGl2YXRpb25fY29sb3VyX3RoZW1lLCBuYW1lID0gIlN0dWR5IG1vdGl2YXRpb24iKSArDQogIHRoZW1lX2NsYXNzaWMoKSArDQogICMgQ3VzdG9taXppbmcgdGhlIHRoZW1lDQogIHRoZW1lKA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC4wNSwgMSksICMgUG9zaXRpb25pbmcgdGhlIGxlZ2VuZCBpbiB0aGUgdG9wLWxlZnQgY29ybmVyIHdpdGhpbiB0aGUgcGxvdA0KICAgIGxlZ2VuZC5qdXN0aWZpY2F0aW9uID0gYygwLCAxKSwgIyBFbnN1cmluZyB0aGUgbGVnZW5kIGJveCBhbGlnbnMgcHJvcGVybHkgYXQgdGhlIHRvcC1sZWZ0IGNvcm5lcg0KICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41KSAjIFJvdGF0aW5nIHgtYXhpcyBsYWJlbHMgZm9yIGJldHRlciByZWFkYWJpbGl0eQ0KICApICsNCiAgIyBBZGRpbmcgYXhpcyBsYWJlbHMNCiAgbGFicygNCiAgICB4ID0gIlllYXIgb2YgcHVibGljYXRpb24iLA0KICAgIHkgPSAiQXJ0aWNsZXMgY3VtdWxhdGl2ZSBncm93dGgiDQogICkNCg0KY3VtdWxhdGl2ZV9hcnRpY2xlc19maWcNCmBgYA0KDQoNCg0KYGBge3IsIHdhcm5pbmc9RkFMU0V9DQpzZXR3ZChmaWd1cmVzX3BhdGgpDQpnZ3NhdmUoInN0dWR5X2N1bXVsYXRpdmVfYXJ0aWNsZXNfZmlnLnBkZiIsIHBsb3QgPSBjdW11bGF0aXZlX2FydGljbGVzX2ZpZywgd2lkdGggPSAxMCwgaGVpZ2h0ID0gNSkNCmBgYA0KDQojIyAxMC4zIFJlbHRpdmUgZ3Jvd3RoDQoNCkxldCdzIGxvb2sgYXQgcmVsYXRpdmUgZ3Jvd3RoIGNvbXBhcmVkIHRvIHRoZSByZXNlYXJjaCBhcmVhIG1vcmUgYnJvYWRseSANCg0KSSB3aWxsIGlkZW50aWZ5IHRoZSBtb3N0IGNvbW1vbiByZXNlYXJjaCBhcmVhIGJhc2VkIG9uIGVhY2ggc3R1ZHkgbW90aXZhdGlvbi4NCg0KRW52aXJvbm1lbnRhbCBtb3RpdmF0aW9uID0gRW52aXJvbm1lbnRhbCBTY2llbmNlcyAmIEVjb2xvZ3kNCk1lZGljYWwgbW90aXZhdGlvbiA9IE5ldXJvc2NpZW5jZXMgJiBOZXVyb2xvZ3kNCkJhc2ljIHJlc2VhcmNoID0gTmV1cm9zY2llbmNlcyAmIE5ldXJvbG9neQ0KDQpgYGB7cn0NCkVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShhcnRpY2xlX2lkKSAlPiUgDQogIGRwbHlyOjpzYW1wbGVfbigxKSAlPiUgDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3R1ZHlfbW90aXZhdGlvbiwgd29zX3Jlc2VhcmNoX2FyZWFzKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBsZW5ndGgoZG9pKSkgJT4lDQogIGRwbHlyOjptdXRhdGUod29zX3Jlc2VhcmNoX2FyZWFzID0gc3RyX3RyaW0od29zX3Jlc2VhcmNoX2FyZWFzKSkgJT4lDQogIHRpZHlyOjpzZXBhcmF0ZV9yb3dzKHdvc19yZXNlYXJjaF9hcmVhcywgc2VwID0gIjsiKSAlPiUgDQogIGRwbHlyOjptdXRhdGUod29zX3Jlc2VhcmNoX2FyZWFzID0gc3RyX3RyaW0od29zX3Jlc2VhcmNoX2FyZWFzKSkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3R1ZHlfbW90aXZhdGlvbiwgd29zX3Jlc2VhcmNoX2FyZWFzKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG5fdG90YWwgPSBzdW0obikpICU+JSANCiAgZHBseXI6OmFycmFuZ2UoZGVzYyhuX3RvdGFsKSkgJT4lIA0KICBkcGx5cjo6YXJyYW5nZShzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIGRwbHlyOjpzbGljZSgxOjIpICU+JSANCiAgZHBseXI6OnVuZ3JvdXAoKQ0KYGBgDQoNCldlIHdpbGwgbm93IGNvbXBhcmUgdGhlIHByb3BvcnRpb24gY3VtdWxhdGl2ZSBncm93dGggb2YgZWFjaCBzdHVkeSBtb3RpdmF0aW9uIGFnYWluc3QgdGhlIG1vc3QgY29tbW9uIHJlc2VhcmNoIGFyZWFzIGJhc2VkIG9uIFdvUy4gDQoNCkkgaGF2ZSBzZWFyY2hlZCAgYXJ0aWNsZXMgcHVibGlzaGVkIHdpdGhpbiB0aGVzZSByZXNlYXJjaCBhcmVhcyBmcm9tIDE5OTItMjAyMiwgYW5kIGNyZWF0ZSBhIGRhdGFiYXNlIHRvIGNvbXBhcmUgYWdhaW5zdC4NCg0KRWFjaCBzZWFyY2ggaW5kdWVkIG9ubHkgYSBkYXRlIHJhbmdlIChlLmcuIFBZPSgxOTkyLTIwMjEpKSBBTkQgdGhlIGdpdmVuIHdlYiBvZiBzY2llbmNlIHJlc2FyY2ggYXJlYSAoZS5nLiBXQz0oUGhhcm1hY29sb2d5ICYgUGhhcm1hY3kpKS4gU2VhcmNoZXJzIHdlcmUgZG9uZSBvbiB0aGUgMDQvMDcvMjAyNC4gT25seSB0aGUgdG90YWwgbnVtYmVyIG9mIGFydGljbGVzIGVhY2ggeWVhciB3YXMgdGFrZW4uIA0KDQpGaXJzdCB3ZSB3aWxsIGltcG9ydCB0aGUgcmVzZWFyY2ggZmllbGQgYW5udWFsIG51bWJlciBvZiBhcnRpY2xlcyBkYXRhYmFzZSBJIGNyZWF0ZSAobWFydGluLWV0LWFsLXN1cHAtZmlsZS05LXdvcy1yZXNlYXJjaC1hcmVhcy0xOTkyLTIwMjIuY3N2KS4gSXQgaXMgcHJvdmlkZSBhcyBzdXBwbGVtZW50YXJ5IGZpbGUgOS4NCg0KYGBge3IsIHdhcm5pbmc9RkFMU0V9DQpzZXR3ZChpbnB1dF9wYXRoKQ0KDQp3b3NfcmVzZWFyY2hfYXJlYXNfbiA8LSByZWFkLmNzdigibWFydGluLWV0LWFsLXN1cHAtZmlsZS05LXdvcy1yZXNlYXJjaC1hcmVhcy0xOTkyLTIwMjIuY3N2IikgJT4lIA0KICBkcGx5cjo6YXJyYW5nZSh5ZWFyKSAlPiUNCiAgZHBseXI6Omdyb3VwX2J5KHJlc2VhcmNoX2FyZWEpICU+JQ0KICBkcGx5cjo6bXV0YXRlKA0KICAgIG5fY3VtdWxhdGl2ZSA9IGN1bXN1bShuKSwgICMgQ2FsY3VsYXRlIHRoZSBjdW11bGF0aXZlIHN1bSBvZiAnbicNCiAgICBuX2N1bXVsYXRpdmVfcHJvcCA9IG5fY3VtdWxhdGl2ZSAvIG1heChuX2N1bXVsYXRpdmUpLCAjIENhbGN1bGF0ZSB0aGUgY3VtdWxhdGl2ZSBwcm9wb3J0aW9uDQogICAgbl8yMDA3ID0gaWZlbHNlKHllYXIgPT0gMjAwNywgbiwgTkFfcmVhbF8pLCAjIEdldCBuIHZhbHVlIGZvciB5ZWFyIDIwMTENCiAgICBuXzIwMDc9IGZpcnN0KG5hLm9taXQobl8yMDA3KSksICMgUHJvcGFnYXRlIHRoZSBuXzIwMTEgdmFsdWUgd2l0aGluIHRoZSBncm91cA0KICAgIG5fcmF0aW9fdG9fMjAwNyA9IG4gLyBuXzIwMDcgIyBDYWxjdWxhdGUgbl9yYXRpb190b18yMDAwDQogICkgJT4lDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lDQogIGRwbHlyOjpzZWxlY3QocmVzZWFyY2hfYXJlYSwgeWVhciwgbiwgbl9jdW11bGF0aXZlLCBuX2N1bXVsYXRpdmVfcHJvcCwgbl9yYXRpb190b18yMDA3KQ0KYGBgDQoNCg0KQ29tYmluZWQgdGhlIG51bWJlciBvZiBhcnRpY2xlcyB3aXRoIHRob3NlIGluIHRoZSBFSVBBQUIgZGF0YWJhc2UNCg0KYGBge3J9DQpwdWJfeWVhcl9ncm93dGhfY29tcCA8LSBwdWJfeWVhcl9ncm93dGggJT4lIA0KICBkcGx5cjo6cmVuYW1lKHJlc2VhcmNoX2FyZWEgPSBzdHVkeV9tb3RpdmF0aW9uKQ0KDQp3b3NfcmVzZWFyY2hfYXJlYXNfY29tcCA8LSB3b3NfcmVzZWFyY2hfYXJlYXNfbiAlPiUgDQogIHJiaW5kKC4sIHB1Yl95ZWFyX2dyb3d0aF9jb21wKSAlPiUgDQogIGRwbHlyOjptdXRhdGUocmVzZWFyY2hfYXJlYSA9IGZhY3RvcihyZXNlYXJjaF9hcmVhLCBsZXZlbHM9YygiRW52aXJvbm1lbnRhbCIsICJNZWRpY2FsIiwgIkJhc2ljIHJlc2VhcmNoIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJFbnZpcm9ubWVudGFsIFNjaWVuY2VzIGFuZCBFY29sb2d5IiwgIlRveGljb2xvZ3kiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5ldXJvc2NpZW5jZXMgYW5kIE5ldXJvbG9neSIsICJQaGFybWFjb2xvZ3kgYW5kIFBoYXJtYWN5IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBbGwgUmVzZWFyY2ggQXJlYXMiKSkpDQpgYGANCg0KDQpMZXQncyBzZWUgd2hhdCB0aGUgcmVsYXRpdmUgZ3Jvd3RoIHdhcyBpbiAyMDIyICh0aGUgbGF0ZXN0IGluY2x1ZGVkIHllYXIgaW4gdGhlIGV2aWRlbmNlIGJhc2UpDQoNCmBgYHtyfQ0Kd29zX3Jlc2VhcmNoX2FyZWFzX2NvbXAgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKHllYXIgPT0gMjAyMikNCmBgYA0KDQoNCiMjIyAxMC4zLjEgRW52aW9ybWVudGFsIHJlbGF0aXZlIGdyb3d0aA0KDQpMZXQncyBub3cgY29tcGFyZSB0aGUgcmVsYXRpdmUgZ3Jvd3RoIGluIEVudmlyb25tZW50YWwgcmVzZWFyY2ggDQoNCmBgYHtyfQ0KIyBEZWZpbmUgdGhlIGNvbG91ciBwYWxldHRlDQplbnZfY29sb3VyX3RoZW1lIDwtIGMoIiM2MEJENkMiLCAiIzJFNEIyMiIsICJibGFjayIpICMgTWFraW5nIGNvbG91ciB0aGVtZSB0byBhcHBseSB0byBwbG90DQoNCmVudmlyb19jb21wIDwtICBjKCJFbnZpcm9ubWVudGFsIiwgIkVudmlyb25tZW50YWwgU2NpZW5jZXMgYW5kIEVjb2xvZ3kiLCAiQWxsIFJlc2VhcmNoIEFyZWFzIikNCg0KbGluZV90eXBlcyA8LSBjKCJFbnZpcm9ubWVudGFsIiA9ICJzb2xpZCIsIA0KICAgICAgICAgICAgICAgICJFbnZpcm9ubWVudGFsIFNjaWVuY2VzIGFuZCBFY29sb2d5IiA9ICJkYXNoZWQiLCANCiAgICAgICAgICAgICAgICAiQWxsIFJlc2VhcmNoIEFyZWFzIiA9ICJzb2xpZCIpDQoNCnJlbGF0aXZlX2dyb3d0aF9lbnZfZmlnIDwtIHdvc19yZXNlYXJjaF9hcmVhc19jb21wICU+JSANCiAgZHBseXI6OmZpbHRlcihyZXNlYXJjaF9hcmVhICVpbiUgZW52aXJvX2NvbXAsIHllYXIgPiAyMDA2KSAlPiUgDQogIGdncGxvdChhZXMoeSA9IG5fcmF0aW9fdG9fMjAwNywgeCA9IHllYXIsIGNvbG91ciA9IHJlc2VhcmNoX2FyZWEsIGxpbmV0eXBlID0gcmVzZWFyY2hfYXJlYSkpICsNCiAgZ2VvbV9saW5lKHN0YXQgPSAiaWRlbnRpdHkiLCBsaW5ld2lkdGggPSAxLjUpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgyMDA3LCAyMDIyLCBieSA9IDEpKSArDQogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAsIDIyKSwgYnJlYWtzID0gc2VxKDAsIDIyLCBieSA9IDQpKSArICMgU2NhbGUgWSBheGlzIGZyb20gMCB0byAyMg0KICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGVudl9jb2xvdXJfdGhlbWUsIG5hbWUgPSAiUmVzZWFyY2ggQXJlYSIpICsNCiAgc2NhbGVfbGluZXR5cGVfbWFudWFsKHZhbHVlcyA9IGxpbmVfdHlwZXMpICsgIyBBcHBseSBtYW51YWwgbGluZSB0eXBlcw0KICBndWlkZXMobGluZXR5cGUgPSAibm9uZSIpICsgIyBSZW1vdmUgbGVnZW5kIGZvciBsaW5lIHR5cGVzDQogIHRoZW1lX2NsYXNzaWMoKSArDQogICMgQ3VzdG9taXppbmcgdGhlIHRoZW1lDQogIHRoZW1lKA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC4wNSwgMSksICMgUG9zaXRpb25pbmcgdGhlIGxlZ2VuZCBpbiB0aGUgdG9wLWxlZnQgY29ybmVyIHdpdGhpbiB0aGUgcGxvdA0KICAgIGxlZ2VuZC5qdXN0aWZpY2F0aW9uID0gYygwLCAxKSwgIyBFbnN1cmluZyB0aGUgbGVnZW5kIGJveCBhbGlnbnMgcHJvcGVybHkgYXQgdGhlIHRvcC1sZWZ0IGNvcm5lcg0KICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41KSAjIFJvdGF0aW5nIHgtYXhpcyBsYWJlbHMgZm9yIGJldHRlciByZWFkYWJpbGl0eQ0KICApICsNCiAgIyBBZGRpbmcgYXhpcyBsYWJlbHMNCiAgbGFicygNCiAgICB4ID0gIlllYXIgb2YgcHVibGljYXRpb24iLA0KICAgIHkgPSAiUmVsYXRpdmUgZ3Jvd3RoIGNvbXBhcmVkIHRvIDIwMDcgKDE1IHllYXIgYmFzZWxpbmUpIg0KICApDQoNCnJlbGF0aXZlX2dyb3d0aF9lbnZfZmlnDQpgYGANCg0KDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCnNldHdkKGZpZ3VyZXNfcGF0aCkNCmdnc2F2ZSgic3R1ZHlfcmVsYXRpdmVfZ3Jvd3RoX2Vudl9maWcucGRmIiwgcGxvdCA9IHJlbGF0aXZlX2dyb3d0aF9lbnZfZmlnLCB3aWR0aCA9IDUsIGhlaWdodCA9IDUpDQpgYGANCg0KDQojIyMgMTAuMy4yIE1lZGljYWwgcmVsYXRpdmUgZ3Jvd3RoDQoNCkNvbXBhcmluZyB0aGUgcmVsYXRpdmUgZ3Jvd3RoIGluIG1lZGljYWwgcmVzZWFyY2ggDQoNCmBgYHtyfQ0KIyBEZWZpbmUgdGhlIGNvbG91ciBwYWxldHRlDQptZWRfY29sb3VyX3RoZW1lIDwtIGMoIiNEMzU5QTEiLCAiI0QyMTM3RiIsICJibGFjayIpICMgTWFraW5nIGNvbG91ciB0aGVtZSB0byBhcHBseSB0byBwbG90DQoNCm1lZF9jb21wIDwtICBjKCJNZWRpY2FsIiwgIk5ldXJvc2NpZW5jZXMgYW5kIE5ldXJvbG9neSIsICJBbGwgUmVzZWFyY2ggQXJlYXMiKQ0KDQpsaW5lX3R5cGVzIDwtIGMoIk1lZGljYWwiID0gInNvbGlkIiwgDQogICAgICAgICAgICAgICAgIk5ldXJvc2NpZW5jZXMgYW5kIE5ldXJvbG9neSIgPSAiZGFzaGVkIiwgDQogICAgICAgICAgICAgICAgIkFsbCBSZXNlYXJjaCBBcmVhcyIgPSAic29saWQiKQ0KDQpyZWxhdGl2ZV9ncm93dGhfbWVkX2ZpZyA8LSB3b3NfcmVzZWFyY2hfYXJlYXNfY29tcCAlPiUgDQogIGRwbHlyOjpmaWx0ZXIocmVzZWFyY2hfYXJlYSAlaW4lIG1lZF9jb21wLCB5ZWFyID4gMjAwNikgJT4lIA0KICBnZ3Bsb3QoYWVzKHkgPSBuX3JhdGlvX3RvXzIwMDcsIHggPSB5ZWFyLCBjb2xvdXIgPSByZXNlYXJjaF9hcmVhLCBsaW5ldHlwZSA9IHJlc2VhcmNoX2FyZWEpKSArDQogIGdlb21fbGluZShzdGF0ID0gImlkZW50aXR5IiwgbGluZXdpZHRoID0gMS41KSArDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMjAwNywgMjAyMiwgYnkgPSAxKSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygwLCAyMiksIGJyZWFrcyA9IHNlcSgwLCAyMiwgYnkgPSA0KSkgKyAjIFNjYWxlIFkgYXhpcyBmcm9tIDAgdG8gMjINCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBtZWRfY29sb3VyX3RoZW1lLCBuYW1lID0gIlJlc2VhcmNoIEFyZWEiKSArDQogIHNjYWxlX2xpbmV0eXBlX21hbnVhbCh2YWx1ZXMgPSBsaW5lX3R5cGVzKSArICMgQXBwbHkgbWFudWFsIGxpbmUgdHlwZXMNCiAgZ3VpZGVzKGxpbmV0eXBlID0gIm5vbmUiKSArICMgUmVtb3ZlIGxlZ2VuZCBmb3IgbGluZSB0eXBlcw0KICB0aGVtZV9jbGFzc2ljKCkgKw0KICAjIEN1c3RvbWl6aW5nIHRoZSB0aGVtZQ0KICB0aGVtZSgNCiAgICBsZWdlbmQucG9zaXRpb24gPSBjKDAuMDUsIDEpLCAjIFBvc2l0aW9uaW5nIHRoZSBsZWdlbmQgaW4gdGhlIHRvcC1sZWZ0IGNvcm5lciB3aXRoaW4gdGhlIHBsb3QNCiAgICBsZWdlbmQuanVzdGlmaWNhdGlvbiA9IGMoMCwgMSksICMgRW5zdXJpbmcgdGhlIGxlZ2VuZCBib3ggYWxpZ25zIHByb3Blcmx5IGF0IHRoZSB0b3AtbGVmdCBjb3JuZXINCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSkgIyBSb3RhdGluZyB4LWF4aXMgbGFiZWxzIGZvciBiZXR0ZXIgcmVhZGFiaWxpdHkNCiAgKSArDQogICMgQWRkaW5nIGF4aXMgbGFiZWxzDQogIGxhYnMoDQogICAgeCA9ICJZZWFyIG9mIHB1YmxpY2F0aW9uIiwNCiAgICB5ID0gIlJlbGF0aXZlIGdyb3d0aCBjb21wYXJlZCB0byAyMDA3ICgxNSB5ZWFyIGJhc2VsaW5lKSINCiAgKQ0KDQpyZWxhdGl2ZV9ncm93dGhfbWVkX2ZpZw0KYGBgDQoNCg0KYGBge3IsIHdhcm5pbmc9RkFMU0V9DQpzZXR3ZChmaWd1cmVzX3BhdGgpDQpnZ3NhdmUoInN0dWR5X3JlbGF0aXZlX2dyb3d0aF9tZWRfZmlnLnBkZiIsIHBsb3QgPSByZWxhdGl2ZV9ncm93dGhfbWVkX2ZpZywgd2lkdGggPSA1LCBoZWlnaHQgPSA1KQ0KYGBgDQoNCg0KIyMjIDEwLjMuMiBCYXNpYyByZXNhcmNoIHJlbGF0aXZlIGdyb3d0aA0KDQpDb21wYXJpbmcgcmVsYXRpdmUgZ3Jvd3RoIGluIGJhc2ljIHJlc2VhcmNoIA0KDQpgYGB7cn0NCiMgRGVmaW5lIHRoZSBjb2xvdXIgcGFsZXR0ZQ0KYmFzaWNfY29sb3VyX3RoZW1lIDwtIGMoIiMzQzgyQzQiLCAiIzI2Mjc2RCIsICJibGFjayIpICMgTWFraW5nIGNvbG91ciB0aGVtZSB0byBhcHBseSB0byBwbG90DQoNCmJhc2ljX2NvbXAgPC0gIGMoIkJhc2ljIHJlc2VhcmNoIiwgIk5ldXJvc2NpZW5jZXMgYW5kIE5ldXJvbG9neSIsICJBbGwgUmVzZWFyY2ggQXJlYXMiKQ0KDQpsaW5lX3R5cGVzIDwtIGMoIkJhc2ljIHJlc2VhcmNoIiA9ICJzb2xpZCIsIA0KICAgICAgICAgICAgICAgICJOZXVyb3NjaWVuY2VzIGFuZCBOZXVyb2xvZ3kiID0gImRhc2hlZCIsIA0KICAgICAgICAgICAgICAgICJBbGwgUmVzZWFyY2ggQXJlYXMiID0gInNvbGlkIikNCg0KcmVsYXRpdmVfZ3Jvd3RoX2Jhc2VfZmlnIDwtIHdvc19yZXNlYXJjaF9hcmVhc19jb21wICU+JSANCiAgZHBseXI6OmZpbHRlcihyZXNlYXJjaF9hcmVhICVpbiUgYmFzaWNfY29tcCwgeWVhciA+IDIwMDYpICU+JSANCiAgZ2dwbG90KGFlcyh5ID0gbl9yYXRpb190b18yMDA3LCB4ID0geWVhciwgY29sb3VyID0gcmVzZWFyY2hfYXJlYSwgbGluZXR5cGUgPSByZXNlYXJjaF9hcmVhKSkgKw0KICBnZW9tX2xpbmUoc3RhdCA9ICJpZGVudGl0eSIsIGxpbmV3aWR0aCA9IDEuNSkgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDIwMDcsIDIwMjIsIGJ5ID0gMSkpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwgMjIpLCBicmVha3MgPSBzZXEoMCwgMjIsIGJ5ID0gNCkpICsgIyBTY2FsZSBZIGF4aXMgZnJvbSAwIHRvIDIyDQogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYmFzaWNfY29sb3VyX3RoZW1lLCBuYW1lID0gIlJlc2VhcmNoIEFyZWEiKSArDQogIHNjYWxlX2xpbmV0eXBlX21hbnVhbCh2YWx1ZXMgPSBsaW5lX3R5cGVzKSArICMgQXBwbHkgbWFudWFsIGxpbmUgdHlwZXMNCiAgZ3VpZGVzKGxpbmV0eXBlID0gIm5vbmUiKSArICMgUmVtb3ZlIGxlZ2VuZCBmb3IgbGluZSB0eXBlcw0KICB0aGVtZV9jbGFzc2ljKCkgKw0KICAjIEN1c3RvbWl6aW5nIHRoZSB0aGVtZQ0KICB0aGVtZSgNCiAgICBsZWdlbmQucG9zaXRpb24gPSBjKDAuMDUsIDEpLCAjIFBvc2l0aW9uaW5nIHRoZSBsZWdlbmQgaW4gdGhlIHRvcC1sZWZ0IGNvcm5lciB3aXRoaW4gdGhlIHBsb3QNCiAgICBsZWdlbmQuanVzdGlmaWNhdGlvbiA9IGMoMCwgMSksICMgRW5zdXJpbmcgdGhlIGxlZ2VuZCBib3ggYWxpZ25zIHByb3Blcmx5IGF0IHRoZSB0b3AtbGVmdCBjb3JuZXINCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSkgIyBSb3RhdGluZyB4LWF4aXMgbGFiZWxzIGZvciBiZXR0ZXIgcmVhZGFiaWxpdHkNCiAgKSArDQogICMgQWRkaW5nIGF4aXMgbGFiZWxzDQogIGxhYnMoDQogICAgeCA9ICJZZWFyIG9mIHB1YmxpY2F0aW9uIiwNCiAgICB5ID0gIlJlbGF0aXZlIGdyb3d0aCBjb21wYXJlZCB0byAyMDA3ICgxNSB5ZWFyIGJhc2VsaW5lKSINCiAgKQ0KDQpyZWxhdGl2ZV9ncm93dGhfYmFzZV9maWcNCmBgYA0KDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQ0Kc2V0d2QoZmlndXJlc19wYXRoKQ0KZ2dzYXZlKCJzdHVkeV9yZWxhdGl2ZV9ncm93dGhfYmFzZV9maWcucGRmIiwgcGxvdCA9IHJlbGF0aXZlX2dyb3d0aF9iYXNlX2ZpZywgd2lkdGggPSA1LCBoZWlnaHQgPSA1KQ0KYGBgDQoNCiMgMTEgUG9wdWxhdGlvbiwgRXhwb3N1cmUgYW5kIE91dGNvbWUNCg0KTG9va2luZyBhdCB0aGUgbGluayBiZXR3ZWVuIHRoZSBQRU8gZWxlbWVudHMuIFdoYXQgd2FzIHRoZSBhdmVyYWdlIHN0dWR5IGRlc2lnbi4NCg0KQmVsb3cgSSBoYXZlIG1hZGUgYSB0YWJsZSB0aGF0IGdyb3VwcyBieSB0aGVzZSBlbGVtZW50cyB0byBzZWUgdGhlIGF2ZXJhZ2Ugc3R1ZHkgZGVzaWduDQoNCkl0IHdhcyAxIGNvbXBvdW5kLCAxIHNwZWNpZXMgYW5kIDEgYmVoYXZpb3VyYWwgY2xhc3MgKDQxJSkNCg0KYGBge3J9DQpiZWhhdl9ib29sZWFuIDwtIGMoImJlaGF2X21vdmVtZW50X2Jvb2xlYW4iLCAiYmVoYXZfYm9sZG5lc3NfYm9vbGVhbiIsICJiZWhhdl9mb3JhZ2luZ19ib29sZWFuIiwgImJlaGF2X2FudGlwcmVkYXRvcl9ib29sZWFuIiwgImJlaGF2X21hdGluZ19ib29sZWFuIiwgImJlaGF2X3Bvc3RfbWF0aW5nX2Jvb2xlYW4iLCAiYmVoYXZfYWdyZXNzaW9uX2Jvb2xlYW4iLCAiYmVoYXZfc29jaWFsaXR5X2Jvb2xlYW4iLCAiYmVoYXZfY29nbml0aW9uX2Jvb2xlYW4iLCAiYmVoYXZfbm9uY2F0X2Jvb2xlYW4iKQ0KDQpFSVBBQUJfZGF0YWJhc2UgJT4lDQogIGRwbHlyOjptdXRhdGUoYmVoYXZfbiA9IHJvd1N1bXMoYWNyb3NzKGFsbF9vZihiZWhhdl9ib29sZWFuKSksIG5hLnJtID0gVFJVRSkpICU+JSAjIGhvdyBtYW55IGJlaGF2IGNsYXNzIG1lYXN1cmVkDQogIGRwbHlyOjpncm91cF9ieShhcnRpY2xlX2lkKSAlPiUgDQogIGRwbHlyOjphcnJhbmdlKGRlc2MoYmVoYXZfbikpICU+JSANCiAgZHBseXI6OnNsaWNlKDEpICU+JSANCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjpzZWxlY3QoY29tcG91bmRfbiwgc3BlY2llc19uLCBiZWhhdl9uKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShjb21wb3VuZF9uLCBzcGVjaWVzX24sIGJlaGF2X24pICU+JSANCiAgZHBseXI6OnJlZnJhbWUobj0gbGVuZ3RoKGNvbXBvdW5kX24pLA0KICAgICAgICAgICAgICAgICAnJScgPSByb3VuZChuLzkwMioxMDAsMSkpICU+JSANCiAgZHBseXI6OmFycmFuZ2UoZGVzYyhuKSkNCmBgYA0KDQpJIHN1bW1hcnkgZGYgdGhhdCBoYXMgdGhlIG51bWJlciBvZiBQRU8gZWxlbWVudHMgaW4gZWFjaCBvZiB0aGUgOTAxIHN0dWRpZXMgDQoNCmBgYHtyfQ0KUEVPX2VsZW1lbnRfc3VtbWFyeSA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lDQogIGRwbHlyOjptdXRhdGUoYmVoYXZfbiA9IHJvd1N1bXMoYWNyb3NzKGFsbF9vZihiZWhhdl9ib29sZWFuKSksIG5hLnJtID0gVFJVRSkpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KGFydGljbGVfaWQpICU+JSANCiAgZHBseXI6OmFycmFuZ2UoZGVzYyhiZWhhdl9uKSkgJT4lIA0KICBkcGx5cjo6c2xpY2UoMSkgJT4lIA0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6OnNlbGVjdChjb21wb3VuZF9uLCBzcGVjaWVzX24sIGJlaGF2X24pDQpgYGANCg0KTG9va2luZyBhdCB0aGUgbnVtYmVyIG9mIHNwZWNpZXMgdXNlZCANCg0KYGBge3J9DQpQRU9fZWxlbWVudF9zdW1tYXJ5ICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHNwZWNpZXNfbikgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gbGVuZ3RoKHNwZWNpZXNfbiksDQogICAgICAgICAgICAgICAgICclJyA9IG4vOTAxKQ0KYGBgDQoNCkxvb2tpbmcgYXQgdGhlIG51bWJlciBvZiBjb21wb3VuZHMgdXNlZCANCg0KYGBge3J9DQpQRU9fZWxlbWVudF9zdW1tYXJ5ICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KGNvbXBvdW5kX24pICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IGxlbmd0aChjb21wb3VuZF9uKSwNCiAgICAgICAgICAgICAgICAgJyUnID0gbi85MDEpDQpgYGANCg0KYGBge3J9DQpQRU9fZWxlbWVudF9zdW1tYXJ5ICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KGJlaGF2X24pICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IGxlbmd0aChzcGVjaWVzX24pLA0KICAgICAgICAgICAgICAgICAnJScgPSBuLzkwMSkNCmBgYA0KDQojIDEyIFNwZWNpZXMNCg0KTGV0J3MgdGFrZSBhIGNsb3NlciBsb29rIGF0IHNwZWNpZXMgaW5mb3JtYXRpb24gDQoNCiMjIDEyLjEgTnVtYmVyIG9mIGRpc3RpY3Qgc3BlY2llcw0KDQpUaGVyZSBhcmUgMTczIHNwZWNpZXMgaW4gdGhlIEVJUEFBQiBkYXRhYmFzZQ0KDQpgYGB7cn0NCkVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIGRwbHlyOjpkaXN0aW5jdChzcGVjaWVzX25hbWUpICU+JSANCiAgbnJvdygpDQpgYGANCg0KVGhlIG51bWJlciBvZiBzcHAgZWFjaCBzdHVkeSBtb3RpdmF0aW9uDQoNCmBgYHtyfQ0KRUlQQUFCX2RhdGFiYXNlICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHN0dWR5X21vdGl2YXRpb24pICU+JSANCiAgZHBseXI6OnJlZnJhbWUobl9zcHAgPSBsZW5ndGgodW5pcXVlKHNwZWNpZXNfbmFtZSkpLA0KICAgICAgICAgICAgICAgICB0b3RhbF9zdHVkeSA9IGxlbmd0aCh1bmlxdWUoYXJ0aWNsZV9pZCkpLA0KICAgICAgICAgICAgICAgICByZWxfbiA9IG5fc3BwL3RvdGFsX3N0dWR5KQ0KYGBgDQoNClRoZXJlIGFyZSAyMSBjbGFzcw0KDQpgYGB7cn0NCkVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIGRwbHlyOjpkaXN0aW5jdChzcGVjaWVzX2NsYXNzKSAlPiUgDQogIG5yb3coKQ0KYGBgDQoNClRoZXJlIGFyZSA5MzUgZGlmZmVyZW50IGdyb3VwcyBvZiBhbmltYWxzIHVzZWQgYWNyb3NzIGFsbCA5MDEgc3R1ZGllcyAoaS5lLiBzb21lIHN0dWRpZXMgaGFkIG1vcmUgdGhlbiBvbmUgc3BlY2llcykgDQoNCmBgYHtyfQ0KRUlQQUFCX2RhdGFiYXNlICU+JSANCiAgZHBseXI6OmRpc3RpbmN0KHVuaXF1ZV9wb3B1bGF0aW9uX2lkKSAlPiUgDQogIG5yb3coLikNCmBgYA0KDQoNCiMjIDEyLjIgTWFqb3IgdGF4YSBncm91cHMNCg0KIyMjIDEyLjIuMSBDbGFkb2dyYW0gKFRheG9ub21pYyB0cmVlKQ0KDQpMZXQncyBtYWtlIGEgQ2xhZG9ncmFtIHRvIGdldCBhbiBvdmVydmlldyBvZiB3aGF0IHRheGEgYXJlIGluIHRoZSBkYXRhYmFzZQ0KDQpgYGB7cn0NCnNwcF90YXhvbm9teSA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lDQogIGRwbHlyOjpncm91cF9ieShzcGVjaWVzX25hbWUpICU+JSANCiAgZHBseXI6OnNhbXBsZV9uKDEpICU+JSANCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIoIWlzLm5hKHNwZWNpZXNfZmFtaWx5KSwgIXN0cl9kZXRlY3Qoc3BlY2llc19zcGVjaWVzLCAic3BwLiIpLCBzcGVjaWVzX2tpbmdkb20gIT0gIkNocm9taXN0YSIpICU+JSANCiAgZHBseXI6OnNlbGVjdCgic3BlY2llc19raW5nZG9tIiwgInNwZWNpZXNfcGh5bHVtIiwgInNwZWNpZXNfY2xhc3MiLCAic3BlY2llc19vcmRlciIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgInNwZWNpZXNfZmFtaWx5IiwgInNwZWNpZXNfZ2VudXMiLCAic3BlY2llc19zcGVjaWVzIikgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHNwZWNpZXNfc3BlY2llcyA9IHBhc3RlMChzdWJzdHIoc3BlY2llc19nZW51cywgMSwgMSksICIuICIsIHN1YigiXlteIF0rICIsICIiLCBzcGVjaWVzX3NwZWNpZXMpKSkNCiMgVGhlIG11dGF0ZSBjaGFuZ2VzIHRoZSBzcHAgbmFtZSB0byBhYmJyZXZpYXRlIHRoZSBHZW51cyAoZS5nLiBBZXNobmEgY3lhbmVhIHRvIEEuIGN5YW5lYSkNCmBgYA0KDQpDcmVhdGUgYSBoaWVyYXJjaGljYWwgc3RydWN0dXJlIGZvciB0aGUgcGxvdA0KDQpgYGB7cn0NCnRheG9ub215IDwtIHNwcF90YXhvbm9teVssIGMoInNwZWNpZXNfa2luZ2RvbSIsICJzcGVjaWVzX3BoeWx1bSIsICJzcGVjaWVzX2NsYXNzIiwgInNwZWNpZXNfb3JkZXIiLCAic3BlY2llc19mYW1pbHkiLCAic3BlY2llc19nZW51cyIsICJzcGVjaWVzX3NwZWNpZXMiKV0NCg0KdGF4b25vbXlbXSA8LSBsYXBwbHkodGF4b25vbXksIGZhY3RvcikNCg0KIyBDcmVhdGUgYSBwaHlsb2dlbmV0aWMgdHJlZQ0KcGh5bG9fdHJlZSA8LSBhcy5waHlsby5mb3JtdWxhKH5zcGVjaWVzX2tpbmdkb20vc3BlY2llc19waHlsdW0vc3BlY2llc19jbGFzcy9zcGVjaWVzX29yZGVyL3NwZWNpZXNfZmFtaWx5L3NwZWNpZXNfZ2VudXMvc3BlY2llc19zcGVjaWVzLCBkYXRhID0gdGF4b25vbXkpDQpgYGANCg0KTWFudWFsIGNyZWF0aW5nIGEgcGh5bG9fdHJlZSAod2l0aCBlcXVhbCBicmFuY2hlcykNCg0KYGBge3J9DQpnZ3RyZWVfb2JqIDwtIGdndHJlZShwaHlsb190cmVlLCBicmFuY2gubGVuZ3RoPSdub25lJywgbGF5b3V0PSdjaXJjdWxhcicpDQoNCiMgRXh0cmFjdCB0aGUgcGh5bHVtIGluZm9ybWF0aW9uIGZvciBjb2xvcmluZw0KI3RheG9ub215JGxhYmVsIDwtIHBhc3RlMChzdWJzdHIoc3BwX3RheG9ub215JHNwZWNpZXNfZ2VudXMsIDEsIDEpLCAiLiAiLCBzcHBfdGF4b25vbXkkc3BlY2llc19zcGVjaWVzKQ0KY2xhc3NfaW5mbyA8LSB0YXhvbm9teSRzcGVjaWVzX2NsYXNzW21hdGNoKHBoeWxvX3RyZWUkdGlwLmxhYmVsLCB0YXhvbm9teSRzcGVjaWVzX3NwZWNpZXMpXQ0KDQojIEFkZCB0aGUgcGh5bHVtIGluZm9ybWF0aW9uIHRvIHRoZSBnZ3RyZWUgb2JqZWN0DQpnZ3RyZWVfb2JqIDwtIGdndHJlZV9vYmogJTwrJSBkYXRhLmZyYW1lKGxhYmVsID0gcGh5bG9fdHJlZSR0aXAubGFiZWwsIGNsYXNzID0gY2xhc3NfaW5mbykNCg0KIyBDcmVhdGUgYSBjb2xvciB2ZWN0b3IgZm9yIHRoZSBwaHlsdW0gbGV2ZWxzDQpjbGFzc19jb2xvcnMgPC0gcmFpbmJvdyhsZW5ndGgodW5pcXVlKGNsYXNzX2luZm8pKSkNCm5hbWVzKGNsYXNzX2NvbG9ycykgPC0gdW5pcXVlKGNsYXNzX2luZm8pDQoNCiMgUGxvdCB0aGUgY2xhZG9ncmFtIHdpdGggY29sb3JlZCBicmFuY2hlcw0Kc3BwX2NsYWRvZ3JhbSA8LSBnZ3RyZWVfb2JqICsNCiAgZ2VvbV90aXBsYWIoc2l6ZT0zKSArICNJZiB5b3Ugd2FudCB0byBhZGQgc3BlY2llcyBuYW1lcw0KICBnZW9tX3RyZWUoYWVzKGNvbG9yPWNsYXNzKSkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY2xhc3NfY29sb3JzKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIpDQpgYGANCg0KDQpgYGB7cn0NCnNwcF9jbGFkb2dyYW0NCmBgYA0KDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQ0Kc2V0d2QoZmlndXJlc19wYXRoKQ0KZ2dzYXZlKCJzcHBfY2xhZG9ncmFtLnBkZiIsIHBsb3QgPSBzcHBfY2xhZG9ncmFtLCB3aWR0aCA9IDgsIGhlaWdodCA9IDUpDQpgYGANCg0KDQojIyMgMTIuMi4yIENsYXNzIGxldmVsDQoNCkxldCdzIGdyb3VwIGJ5IGNsYXNzIHRvIHNlZSB0aGUgbWFqb3IgdGF4b25vbWljIENsYXNzZXMgdXNlZA0KDQpGaXJzdCByZW1vdmluZyBjYXNlcyB3aGVyZSBzcGVjaWVzX3NwZWNpZXMgd2FzICJzcHAuIiByZXBsYWNpbmcgd2l0aCBOQSBmb3IgdGF4b25vbWljIGNsYXNzaWZpY2F0aW9uDQoNCmBgYHtyfQ0KRUlQQUFCX2RhdGFiYXNlIDwtIEVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIGRwbHlyOjptdXRhdGUoc3BlY2llc19zcGVjaWVzID0gaWZfZWxzZShzcGVjaWVzX3NwZWNpZXMgPT0gInNwcC4iLCBOQSwgc3BlY2llc19zcGVjaWVzKSkNCmBgYA0KDQpMZXQncyBsb29rIGF0IHRoZSBtYWpvciBDbGFzcw0KDQpgYGB7cn0NCiMgVG90YWwgbnVtYmVyIG9mIHNwcA0Kbl9zcHAgPC0gRUlQQUFCX2RhdGFiYXNlICU+JSANCiAgZHBseXI6OmRpc3RpbmN0KHNwZWNpZXNfbmFtZSkgJT4lIA0KICBucm93KCkgDQoNCiMgTnVtYmVyIG9mIHNwcCBwZXIgQ2xhc3MgYW5kIHBlciBwaHlsdW0gDQpzcHBfY2xhc3NlcyA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3BlY2llc19jbGFzcywgc3BlY2llc19waHlsdW0pICU+JSANCiAgZHBseXI6OnJlZnJhbWUoY291bnRfY2xhc3MgPSBsZW5ndGgodW5pcXVlKHNwZWNpZXNfbmFtZSkpLA0KICAgICAgICAgICAgICAgICBwZXJjZW50X2NsYXNzID0gcm91bmQoY291bnRfY2xhc3Mvbl9zcHAqMTAwLDEpKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzcGVjaWVzX3BoeWx1bSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKGNvdW50X3BoeWx1bSA9IHN1bShjb3VudF9jbGFzcyksDQogICAgICAgICAgICAgICAgcGVyY2VudF9waHlsdW0gPSByb3VuZChjb3VudF9waHlsdW0vbl9zcHAqMTAwLDEpKSAlPiUgDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6YXJyYW5nZShkZXNjKHBlcmNlbnRfY2xhc3MpKQ0KICANCg0Kc3BwX2NsYXNzZXMgJT4lIA0KICBkcGx5cjo6c2xpY2UoMToxMCkNCmBgYA0KTWFraW5nIGEgZmlndXJlIGZvciB0aGUgMTUgbW9zdCBhYnVuZGFudCBDbGFzcywgaXQgdGVybXMgb2Ygc3BlY2llcyBkaXZlcnNpdHkgaW4gdGhlIEVJUEFBQiBkYXRhYmFzZQ0KDQpgYGB7cn0NCmNsYXNzX25fc3BwX2ZpZyA8LSBzcHBfY2xhc3NlcyAlPiUgDQogIGRwbHlyOjphcnJhbmdlKGRlc2MocGVyY2VudF9jbGFzcykpICU+JSAjIGFycmFuZ2UgdGhlIGRhdGFzZXQNCiAgZHBseXI6OnNsaWNlKDE6MTUpICU+JSAjIFRha2Ugb25seSB0aGUgbW9zdCBkaXZlcnNlIDE1IENsYXNzDQogIGRwbHlyOjptdXRhdGUoc3BlY2llc19jbGFzcyA9IGZjdF9yZW9yZGVyKHNwZWNpZXNfY2xhc3MsIHBlcmNlbnRfY2xhc3MpLCAjIE9yZGVyIGJ5IGRpdmVyc2l0eQ0KICAgICAgICAgICAgICAgIHNwZWNpZXNfcGh5bHVtID0gZmN0X3Jlb3JkZXIoc3BlY2llc19waHlsdW0sIGRlc2MocGVyY2VudF9waHlsdW0pKSkgJT4lICMgT3JkZXIgYnkgZGl2ZXJzaXR5DQogIGdncGxvdChhZXMoeD1zcGVjaWVzX2NsYXNzLCB5PWNvdW50X2NsYXNzLCBjb2xvciA9IHNwZWNpZXNfcGh5bHVtKSkgKw0KICBnZW9tX3NlZ21lbnQoYWVzKHg9c3BlY2llc19jbGFzcywgeGVuZD1zcGVjaWVzX2NsYXNzLCB5PTAsIHllbmQ9Y291bnRfY2xhc3MpKSArDQogIGdlb21fcG9pbnQoc2l6ZT00KSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBjb3VudF9jbGFzcyksIA0KICAgICAgICAgICAgaGp1c3Q9LTEuMiwgDQogICAgICAgICAgICBzaXplPTMuNSwgDQogICAgICAgICAgICBjb2xvcj0iYmxhY2siKSArDQogIHNjYWxlX2NvbG91cl9icmV3ZXIocGFsZXR0ZT0gIkRhcmsyIikgKw0KICBjb29yZF9mbGlwKCkgKw0KICB5bGltKDAsIDc1KSArDQogIHRoZW1lX2NsYXNzaWMoKSArDQogICBsYWJzKA0KICAgIHggPSAiIiwNCiAgICB5ID0gIk51bWJlciBvZiBkaXN0aWN0IHNwZWNpZXMgaW4gdGhlIGRhdGFiYXNlIg0KICApICsNCiAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC4sIDAuMDUpLCAgIyBQb3NpdGlvbmluZyB0aGUgbGVnZW5kIGluc2lkZSB0aGUgcGxvdA0KICAgIGxlZ2VuZC5qdXN0aWZpY2F0aW9uID0gYygtMywgMCksICAgIyBCb3R0b20gbGVmdCBpbnNpZGUgdGhlIHBsb3QNCiAgICBsZWdlbmQuYm94Lmp1c3QgPSAicmlnaHQiLA0KICAgIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGw9YWxwaGEoJ3doaXRlJywgMC41KSkNCiAgICkNCg0KY2xhc3Nfbl9zcHBfZmlnDQpgYGANCg0KU2F2ZSB0aGUgZmlndXJlDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQ0Kc2V0d2QoZmlndXJlc19wYXRoKQ0KZ2dzYXZlKCJzcHBfY2xhc3Nfbl9zcHBfZmlnLnBkZiIsIHBsb3QgPSBjbGFzc19uX3NwcF9maWcsIHdpZHRoID0gNSwgaGVpZ2h0ID0gNSkNCmBgYA0KDQojIyMgMTIuMi4zIFBoeWx1bSBsZXZlbA0KDQpIZXJlJ3MgYSBsb29rIGF0IHRoZSAlIGF0IHRoZSBwaHlsdW0gbGV2ZWwgDQoNCmBgYHtyfQ0KIyBJbiB0aGUgY2xhc3Mgc3VtbWFyeSB3ZSBhbHNvIGluY2x1ZGVkIHBlcmNlbnRfcGh5bHVtDQpzcHBfY2xhc3NlcyAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzcGVjaWVzX3BoeWx1bSkgJT4lIA0KICBkcGx5cjo6c2FtcGxlX24oMSkgJT4lIA0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6OnNlbGVjdCgtc3BlY2llc19jbGFzcywgLWNvdW50X2NsYXNzLCAtcGVyY2VudF9jbGFzcykgJT4lIA0KICBkcGx5cjo6YXJyYW5nZShkZXNjKHBlcmNlbnRfcGh5bHVtKSkNCmBgYA0KDQpBIHJpbmcgY2hhcnQgYXQgdGhlIHBoeWx1bSBsZXZlbA0KDQpgYGB7cn0NCnJpbmdfcGxvdF9kZiA8LSBzcHBfY2xhc3NlcyAlPiUgDQogIGRwbHlyOjpzbGljZSgxOjE1KSAlPiUNCiAgZHBseXI6Omdyb3VwX2J5KHNwZWNpZXNfcGh5bHVtKSAlPiUgDQogIGRwbHlyOjpzYW1wbGVfbigxKSAlPiUgDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6c2VsZWN0KHNwZWNpZXNfcGh5bHVtLCBjb3VudF9waHlsdW0pICU+JSANCiAgZHBseXI6Om11dGF0ZShwZXJjZW50X3BoeWx1bSA9IGNvdW50X3BoeWx1bS9zdW0oY291bnRfcGh5bHVtKSkgJT4lIA0KICBkcGx5cjo6YXJyYW5nZShkZXNjKHBlcmNlbnRfcGh5bHVtKSkNCg0KIyBDb21wdXRlIHRoZSBjdW11bGF0aXZlIHBlcmNlbnRhZ2VzICh0b3Agb2YgZWFjaCByZWN0YW5nbGUpDQpyaW5nX3Bsb3RfZGYkeW1heCA9IGN1bXN1bShyaW5nX3Bsb3RfZGYkcGVyY2VudF9waHlsdW0pDQoNCiMgQ29tcHV0ZSB0aGUgYm90dG9tIG9mIGVhY2ggcmVjdGFuZ2xlDQpyaW5nX3Bsb3RfZGYkeW1pbiA9IGMoMCwgaGVhZChyaW5nX3Bsb3RfZGYkeW1heCwgbj0tMSkpDQoNCiMgQ29tcHV0ZSBsYWJlbCBwb3NpdGlvbg0KcmluZ19wbG90X2RmJGxhYmVsUG9zaXRpb24gPC0gKHJpbmdfcGxvdF9kZiR5bWF4ICsgcmluZ19wbG90X2RmJHltaW4pIC8gMg0KDQojIENvbXB1dGUgYSBnb29kIGxhYmVsDQpyaW5nX3Bsb3RfZGYkbGFiZWwgPC0gcGFzdGUwKHJpbmdfcGxvdF9kZiRzcGVjaWVzX3BoeWx1bSwgIlxuIChuID0gIiwgcmluZ19wbG90X2RmJGNvdW50X3BoeWx1bSwgIikiKQ0KDQoNCnBoeWx1bV9yaW5nX2ZpZyA8LSByaW5nX3Bsb3RfZGYgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHNwZWNpZXNfcGh5bHVtID0gZmN0X3Jlb3JkZXIoc3BlY2llc19waHlsdW0sIGRlc2MocGVyY2VudF9waHlsdW0pKSkgJT4lIA0KICBnZ3Bsb3QoYWVzKHltYXg9eW1heCwgeW1pbj15bWluLCB4bWF4PTQsIHhtaW49MywgZmlsbD1zcGVjaWVzX3BoeWx1bSkpICsNCiAgZ2VvbV9yZWN0KCkgKw0KICBjb29yZF9wb2xhcih0aGV0YT0ieSIpICsgDQogIGdlb21fbGFiZWwoeD01LCBhZXMoeT1sYWJlbFBvc2l0aW9uLCBsYWJlbD1sYWJlbCksIHNpemU9MywgYWxwaGEgPSAwLjgpICsNCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZT0gIkRhcmsyIikgKw0KICB4bGltKGMoMiwgNSkpICsNCiAgdGhlbWVfdm9pZCgpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KDQpwaHlsdW1fcmluZ19maWcNCmBgYA0KDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQ0Kc2V0d2QoZmlndXJlc19wYXRoKQ0KZ2dzYXZlKCJzcHBfcGh5bHVtX3JpbmdfZmlnLnBkZiIsIHBsb3QgPSBwaHlsdW1fcmluZ19maWcsIHdpZHRoID0gNSwgaGVpZ2h0ID0gNSkNCmBgYA0KDQoNCiMjIDEyLjMgVGF4YSByZXByZXNlbnRhdGlvbg0KDQpOb3cgd2Ugd2lsbCBsb29rIGF0IGhvdyBtYW55IHRpbWVzIGVhY2ggcGh5bHVtLCBjbGFzcywgb3JkZXIsIGZhbWlseSwgZ2VudXMsIHNwZWNpZXMgYXBwZWFyIGluIHRoZSBkYXRhYmFzZQ0KDQpGaXJzdCB3ZSB3aWxsIG1ha2UgYSBkYXRhc2V0IHRoYXQgY291bnRzIHRoZSBudW1iZXIgb2Ygc3BlY2llcyB3aXRoaW4gZWFjaCBwaHlsdW0sIGNsYXNzLCBvcmRlciwgZmFtaWx5LCBhbmQgZ2VudXMuDQoNCmBgYHtyfQ0KIyBTdGVwIDE6IFNlcGFyYXRlIGFuZCBwaXZvdCB0aGUgZGF0YQ0KbGluZWFnZV9kYXRhIDwtIEVJUEFBQl9kYXRhYmFzZSAlPiUNCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBjKCJzcGVjaWVzX3BoeWx1bSIsICJzcGVjaWVzX2NsYXNzIiwgInNwZWNpZXNfb3JkZXIiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICJzcGVjaWVzX2ZhbWlseSIsICJzcGVjaWVzX2dlbnVzIiwgInNwZWNpZXNfc3BlY2llcyIpLCANCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gImxpbmVhZ2VfbGV2ZWwiLCB2YWx1ZXNfdG8gPSAiY2xhc3NpZmljYXRpb24iKSAlPiUNCiAgZHBseXI6Om11dGF0ZShsaW5lYWdlX2xldmVsID0gc3RyX3JlbW92ZShsaW5lYWdlX2xldmVsLCAic3BlY2llc18iKSkNCg0KDQojIERlZmluZSB0aGUgb3JkZXINCmxpbmVhZ2VfbGV2ZWxzX29yZGVyIDwtIGMoInBoeWx1bSIsICJjbGFzcyIsICJvcmRlciIsICJmYW1pbHkiLCAiZ2VudXMiLCAic3BlY2llcyIpDQoNCiMgU3RlcCAyOiBDcmVhdGUgcGFyZW50LWNoaWxkIHJlbGF0aW9uc2hpcHMNCmxpbmVhZ2VfZGF0YSA8LSBsaW5lYWdlX2RhdGEgJT4lDQogIGdyb3VwX2J5KHVuaXF1ZV9yb3dfaWQpICU+JQ0KICBtdXRhdGUocGFyZW50ID0gY2FzZV93aGVuKA0KICAgIGxpbmVhZ2VfbGV2ZWwgPT0gInBoeWx1bSIgfiAiQW5pbWFsaWEiLA0KICAgIGxpbmVhZ2VfbGV2ZWwgPT0gImNsYXNzIiB+IGxhZyhjbGFzc2lmaWNhdGlvbiwgMSksDQogICAgbGluZWFnZV9sZXZlbCA9PSAib3JkZXIiIH4gbGFnKGNsYXNzaWZpY2F0aW9uLCAxKSwNCiAgICBsaW5lYWdlX2xldmVsID09ICJmYW1pbHkiIH4gbGFnKGNsYXNzaWZpY2F0aW9uLCAxKSwNCiAgICBsaW5lYWdlX2xldmVsID09ICJnZW51cyIgfiBsYWcoY2xhc3NpZmljYXRpb24sIDEpLA0KICAgIGxpbmVhZ2VfbGV2ZWwgPT0gInNwZWNpZXMiIH4gbGFnKGNsYXNzaWZpY2F0aW9uLCAxKSwNCiAgKSkgJT4lDQogIHVuZ3JvdXAoKQ0KYGBgDQoNCkhlcmUgd2Ugc3VtIHRoZSB0b3RhbCBudW1iZXIgb2Ygc3BlY2llcyB1c2VkIGluIHRoZSBkYXRhYmFzZSBhY3Jvc3MgZWFjaCB0YXhvbm9taWMgY2xhc3NpZmljYXRpb24NCiAgICAgICAgICAgICAgICANCmBgYHtyfQ0Kbl9yb3dzIDwtIEVJUEFBQl9kYXRhYmFzZSAlPiUNCiAgbnJvdygpDQoNCmxpbmVhZ2VfY291bnRfdXNlIDwtIGxpbmVhZ2VfZGF0YSAlPiUNCiAgZHBseXI6Omdyb3VwX2J5KGNsYXNzaWZpY2F0aW9uLCBsaW5lYWdlX2xldmVsLCBwYXJlbnQpICU+JQ0KICBkcGx5cjo6cmVmcmFtZShjbGFzc2lmaWNhdGlvbl9jb3VudCA9IGxlbmd0aCh1bmlxdWVfcm93X2lkKSwNCiAgICAgICAgICAgICAgICBjbGFzc2lmaWNhdGlvbl9wZXJjZW50ID0gcm91bmQoY2xhc3NpZmljYXRpb25fY291bnQvbl9yb3dzKjEwMCwxKSkNCmBgYA0KDQpNYWtpbmcgYSBwbG90IHRvIGxvb2sgYXQgdGhlIDE1IG1vc3QgY29tbW9ubHkgdXNlZCBjbGFzcywgYnV0IHlvdSBjYW4gZG8gdGhpcyBhdCBhbnkgb2YgdGhlIHRheG9ub21pYyBsZXZlbHMNCg0KYGBge3J9DQpjbGFzc191c2VfZmlnIDwtIGxpbmVhZ2VfY291bnRfdXNlICU+JSANCiAgZHBseXI6OmZpbHRlcihsaW5lYWdlX2xldmVsID09ICJjbGFzcyIpICU+JSANCiAgZHBseXI6OmFycmFuZ2UoZGVzYyhjbGFzc2lmaWNhdGlvbl9wZXJjZW50KSkgJT4lIA0KICBkcGx5cjo6c2xpY2UoMToxNSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKGNsYXNzaWZpY2F0aW9uID0gZmN0X3Jlb3JkZXIoY2xhc3NpZmljYXRpb24sIGNsYXNzaWZpY2F0aW9uX3BlcmNlbnQpLA0KICAgICAgICAgICAgICAgIHBhcmVudCA9IGZjdF9yZW9yZGVyKHBhcmVudCwgZGVzYyhjbGFzc2lmaWNhdGlvbl9wZXJjZW50KSkpICU+JQ0KICBnZ3Bsb3QoYWVzKHg9Y2xhc3NpZmljYXRpb24sIHk9Y2xhc3NpZmljYXRpb25fcGVyY2VudCwgY29sb3IgPSBwYXJlbnQpKSArDQogIGdlb21fc2VnbWVudChhZXMoeD1jbGFzc2lmaWNhdGlvbiwgeGVuZD1jbGFzc2lmaWNhdGlvbiwgeT0wLCB5ZW5kPWNsYXNzaWZpY2F0aW9uX3BlcmNlbnQpKSArDQogIGdlb21fcG9pbnQoc2l6ZT00KSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBwYXN0ZTAocm91bmQoY2xhc3NpZmljYXRpb25fcGVyY2VudCwyKSwgIiUiKSksIA0KICAgICAgICAgICAgaGp1c3Q9LTAuNSwgDQogICAgICAgICAgICBzaXplPTMuNSwgDQogICAgICAgICAgICBjb2xvcj0iYmxhY2siKSArDQogIHNjYWxlX2NvbG91cl9icmV3ZXIocGFsZXR0ZT0gIkRhcmsyIikgKw0KICBjb29yZF9mbGlwKCkgKw0KICB5bGltKDAsIDEwMCkgKw0KICB0aGVtZV9jbGFzc2ljKCkgKw0KICAgbGFicygNCiAgICB4ID0gIiIsDQogICAgeSA9ICJQZXJjZW50YWdlIHJlcHJlc2VudGF0aW9uIGluIHRoZSBkYXRhYmFzZSINCiAgKSArDQogICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSBjKDAuLCAwLjA1KSwgICMgUG9zaXRpb25pbmcgdGhlIGxlZ2VuZCBpbnNpZGUgdGhlIHBsb3QNCiAgICBsZWdlbmQuanVzdGlmaWNhdGlvbiA9IGMoLTMsIDApLCAgICMgQm90dG9tIGxlZnQgaW5zaWRlIHRoZSBwbG90DQogICAgbGVnZW5kLmJveC5qdXN0ID0gInJpZ2h0IiwNCiAgICBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsPWFscGhhKCd3aGl0ZScsIDAuNSkpDQogICApDQoNCmNsYXNzX3VzZV9maWcNCmBgYA0KDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQ0Kc2V0d2QoZmlndXJlc19wYXRoKQ0KZ2dzYXZlKCJzcHBfY2xhc3NfdXNlX2ZpZy5wZGYiLCBwbG90ID0gY2xhc3NfdXNlX2ZpZywgd2lkdGggPSA1LCBoZWlnaHQgPSA1KQ0KYGBgDQoNCg0KYGBge3J9DQpsaW5lYWdlX2NvdW50X3VzZSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIobGluZWFnZV9sZXZlbCA9PSAiY2xhc3MiKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShjbGFzc2lmaWNhdGlvbikgJT4lIA0KICBkcGx5cjo6c2FtcGxlX24oMSkgJT4lIA0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6OmFycmFuZ2UoZGVzYyhjbGFzc2lmaWNhdGlvbl9wZXJjZW50KSkNCmBgYA0KDQpIZXJlJ3MgYnJlYWsgZG93biBieSBQaHlsdW0NCg0KYGBge3J9DQpyaW5nX3VzZV9wbG90X2RmIDwtIGxpbmVhZ2VfY291bnRfdXNlICU+JSANCiAgZHBseXI6OmZpbHRlcihsaW5lYWdlX2xldmVsID09ICJwaHlsdW0iKSAlPiUgDQogIGRwbHlyOjphcnJhbmdlKGRlc2MoY2xhc3NpZmljYXRpb25fcGVyY2VudCkpICU+JSANCiAgZHBseXI6Om11dGF0ZShjbGFzc2lmaWNhdGlvbl9wZXJjZW50ID0gcm91bmQoY2xhc3NpZmljYXRpb25fcGVyY2VudCwgMikpICU+JSANCiAgZHBseXI6OnNsaWNlKDE6OCkNCg0KIyBDb21wdXRlIHRoZSBjdW11bGF0aXZlIHBlcmNlbnRhZ2VzICh0b3Agb2YgZWFjaCByZWN0YW5nbGUpDQpyaW5nX3VzZV9wbG90X2RmJHltYXggPSBjdW1zdW0ocmluZ191c2VfcGxvdF9kZiRjbGFzc2lmaWNhdGlvbl9wZXJjZW50KQ0KDQojIENvbXB1dGUgdGhlIGJvdHRvbSBvZiBlYWNoIHJlY3RhbmdsZQ0KcmluZ191c2VfcGxvdF9kZiR5bWluID0gYygwLCBoZWFkKHJpbmdfdXNlX3Bsb3RfZGYkeW1heCwgbj0tMSkpDQoNCiMgQ29tcHV0ZSBsYWJlbCBwb3NpdGlvbg0KcmluZ191c2VfcGxvdF9kZiRsYWJlbFBvc2l0aW9uIDwtIChyaW5nX3VzZV9wbG90X2RmJHltYXggKyByaW5nX3VzZV9wbG90X2RmJHltaW4pIC8gMg0KDQojIENvbXB1dGUgYSBnb29kIGxhYmVsDQpyaW5nX3VzZV9wbG90X2RmJGxhYmVsIDwtIHBhc3RlMChyaW5nX3VzZV9wbG90X2RmJGNsYXNzaWZpY2F0aW9uLCAiXG4gKCIsIHJpbmdfdXNlX3Bsb3RfZGYkY2xhc3NpZmljYXRpb25fcGVyY2VudCwgIiUpIikNCg0KDQpwaHlsdW1fdXNlX3JpbmdfZmlnIDwtIHJpbmdfdXNlX3Bsb3RfZGYgJT4lIA0KICBkcGx5cjo6bXV0YXRlKGNsYXNzaWZpY2F0aW9uID0gZmN0X3Jlb3JkZXIoY2xhc3NpZmljYXRpb24sIGRlc2MoY2xhc3NpZmljYXRpb25fcGVyY2VudCkpKSAlPiUgDQogIGdncGxvdChhZXMoeW1heD15bWF4LCB5bWluPXltaW4sIHhtYXg9NCwgeG1pbj0zLCBmaWxsPWNsYXNzaWZpY2F0aW9uKSkgKw0KICBnZW9tX3JlY3QoKSArDQogIGNvb3JkX3BvbGFyKHRoZXRhPSJ5IikgKyANCiAgZ2VvbV9sYWJlbCh4PTUsIGFlcyh5PWxhYmVsUG9zaXRpb24sIGxhYmVsPWxhYmVsKSwgc2l6ZT0zLCBhbHBoYSA9IDAuOCkgKw0KICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlPSAiRGFyazIiKSArDQogIHhsaW0oYygyLCA1KSkgKw0KICB0aGVtZV92b2lkKCkgDQogICN0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpDQoNCnBoeWx1bV91c2VfcmluZ19maWcNCmBgYA0KDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQ0Kc2V0d2QoZmlndXJlc19wYXRoKQ0KZ2dzYXZlKCJzcHBfcGh5bHVtX3VzZV9yaW5nX2ZpZy5wZGYiLCBwbG90ID0gcGh5bHVtX3VzZV9yaW5nX2ZpZywgd2lkdGggPSA1LCBoZWlnaHQgPSA1KQ0KYGBgDQoNCiMjIyAxMi4zLjIgVGF4YSByZXByZXNlbnRhdGlvbiBieSBzdHVkeSBtb3RpdmF0aW9uDQoNCk1ha2luZyBhIGRhdGEgc2V0IHRoYXQgbG9va3MgYXQgcmVsYXRpdmUgcmVwcmVzZW50YXRpb24gYnkgZWFjaCBtb3RpdmF0aW9uLCBhbmQgdGhlIHRvdGFsDQoNCmBgYHtyfQ0KbGluZWFnZV9jb3VudF91c2VfbW90aXZhdGlvbiA8LSBsaW5lYWdlX2RhdGEgJT4lDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uLCBsaW5lYWdlX2xldmVsLCBwYXJlbnQsIGNsYXNzaWZpY2F0aW9uKSAlPiUNCiAgZHBseXI6OnJlZnJhbWUoY2xhc3NpZmljYXRpb25fY291bnQgPSBsZW5ndGgodW5pcXVlX3Jvd19pZCkpICU+JQ0KICBkcGx5cjo6Z3JvdXBfYnkoc3R1ZHlfbW90aXZhdGlvbiwgbGluZWFnZV9sZXZlbCkgJT4lDQogIGRwbHlyOjptdXRhdGUobl9tb3RpdmF0aW9uID0gc3VtKGNsYXNzaWZpY2F0aW9uX2NvdW50KSkgJT4lDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKGNsYXNzaWZpY2F0aW9uX3BlcmNlbnQgPSAoY2xhc3NpZmljYXRpb25fY291bnQvbl9tb3RpdmF0aW9uKSoxMDApDQoNCmxpbmVhZ2VfY291bnRfdXNlX2FsbCA8LSBsaW5lYWdlX2RhdGEgJT4lDQogIGRwbHlyOjpncm91cF9ieShsaW5lYWdlX2xldmVsLCBwYXJlbnQsIGNsYXNzaWZpY2F0aW9uKSAlPiUNCiAgZHBseXI6OnJlZnJhbWUoY2xhc3NpZmljYXRpb25fY291bnQgPSBsZW5ndGgodW5pcXVlX3Jvd19pZCkpICU+JQ0KICBkcGx5cjo6Z3JvdXBfYnkobGluZWFnZV9sZXZlbCkgJT4lDQogIGRwbHlyOjptdXRhdGUobl9tb3RpdmF0aW9uID0gc3VtKGNsYXNzaWZpY2F0aW9uX2NvdW50KSkgJT4lDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKGNsYXNzaWZpY2F0aW9uX3BlcmNlbnQgPSAoY2xhc3NpZmljYXRpb25fY291bnQvbl9tb3RpdmF0aW9uKSoxMDApICU+JSANCiAgZHBseXI6Om11dGF0ZShzdHVkeV9tb3RpdmF0aW9uID0gIkFsbCIpDQoNCmxpbmVhZ2VfY291bnRfdXNlX21vdGl2YXRpb24gPC0gbGluZWFnZV9jb3VudF91c2VfbW90aXZhdGlvbiAlPiUgDQogIHJiaW5kKC4sIGxpbmVhZ2VfY291bnRfdXNlX2FsbCkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHN0dWR5X21vdGl2YXRpb24gPSBmY3RfcmVsZXZlbChzdHVkeV9tb3RpdmF0aW9uLCAiQWxsIiwgIkVudmlyb25tZW50YWwiLCAiTWVkaWNhbCIsICJCYXNpYyByZXNlYXJjaCIpKQ0KYGBgDQoNCkhlcmUncyBhIHRpbGUgcGxvdCB0byBjb21wYXJlIHRoZSB1c2Ugb2YgZGlmZmVyZW50IHRheGEgYWNyb3NzIHRoZSBzdHVkeSBtb3RpdmF0aW9ucw0KDQpgYGB7cn0NCmNsYXNzX29yZGVyX2RmIDwtIGxpbmVhZ2VfY291bnRfdXNlICU+JSANCiAgZHBseXI6OmZpbHRlcihsaW5lYWdlX2xldmVsID09ICJjbGFzcyIpICU+JSANCiAgZHBseXI6OmFycmFuZ2UoY2xhc3NpZmljYXRpb25fcGVyY2VudCkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKGNsYXNzX29yZGVyID0gMTpucm93KC4pKSAlPiUgDQogIGRwbHlyOjpzZWxlY3QoY2xhc3NpZmljYXRpb24sIGNsYXNzX29yZGVyKQ0KDQoNCmNsYXNzX3VzZV9tb3RpdmF0aW9uX2ZpZyA8LSBsaW5lYWdlX2NvdW50X3VzZV9tb3RpdmF0aW9uICU+JSANCiAgZHBseXI6OmZpbHRlcihsaW5lYWdlX2xldmVsID09ICJjbGFzcyIpICU+JSANCiAgZHBseXI6OmZ1bGxfam9pbiguLCBjbGFzc19vcmRlcl9kZiwgYnkgPSAiY2xhc3NpZmljYXRpb24iKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoY2xhc3NpZmljYXRpb24gPSBmY3RfcmVvcmRlcihjbGFzc2lmaWNhdGlvbiwgY2xhc3Nfb3JkZXIpLA0KICAgICAgICAgICAgICAgIHBhcmVudCA9IGZjdF9yZW9yZGVyKHBhcmVudCwgZGVzYyhjbGFzc19vcmRlcikpKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gc3R1ZHlfbW90aXZhdGlvbiwgeSA9IGNsYXNzaWZpY2F0aW9uLCBmaWxsID0gY2xhc3NpZmljYXRpb25fcGVyY2VudCkpICsNCiAgZ2VvbV90aWxlKCkgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGFzdGUwKHJvdW5kKGNsYXNzaWZpY2F0aW9uX3BlcmNlbnQsIDEpLCIlIikpKSArDQogIHNjYWxlX2ZpbGxfZ3JhZGllbnQobmFtZSA9IGV4cHJlc3Npb24oIlJlbGF0aXZlXG5hYnVkYW5jZSAoJSkiKSwNCiAgICAgICAgICAgICAgICAgICAgICBsb3cgPSAiI0ZGRkZGRiIsIGhpZ2ggPSAiIzIzMUYyMCIpICsNCiAgdGhlbWVfY2xhc3NpYygpICsNCiAgbGFicyh4ID0gIlN0dWR5IG1vdGl2YXRpb24iLA0KICAgICAgIHkgPSAiVGF4b25vbWljIGNsYXNzIikNCmNsYXNzX3VzZV9tb3RpdmF0aW9uX2ZpZw0KYGBgDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQ0Kc2V0d2QoZmlndXJlc19wYXRoKQ0KZ2dzYXZlKCJzcHBfY2xhc3NfdXNlX21vdGl2YXRpb25fZmlnLnBkZiIsIHBsb3QgPSBjbGFzc191c2VfbW90aXZhdGlvbl9maWcsIHdpZHRoID0gNSwgaGVpZ2h0ID0gNSkNCmBgYA0KDQoNCiMjIyAxMi4zLjMgTW9zdCBjb21tb24gc3BlY2llcyANCg0KTGV0J3Mgc2VlIHdoYXQgdGhlIG1vc3QgY29tbW9uIHNwZWNpZXMgd2VyZS4gVGhpcyBpcyBjYWxjdWxhdGVkIGF0IHRoZSBwb3B1bGF0aW9uIGxldmVsIChpLmUuIGRvZXNuJ3QgY291bnQgZWFjaCBzcGVjaWVzIG11dGlwbGUgdGltZXMgaWYgbXVsdGlwbGUgY29tcG91bmRzIHdlcmUgdXNlZCBpbiBhIHNpbmdsZSBhcnRpY2xlOyB1bmlxdWVfcG9wdWxhdGlvbl9pZCkNCg0KYGBge3J9DQpuX3RvdGFsIDwtIEVJUEFBQl9kYXRhYmFzZSAlPiUNCiAgZHBseXI6Omdyb3VwX2J5KHVuaXF1ZV9wb3B1bGF0aW9uX2lkKSAlPiUgDQogIGRwbHlyOjpzYW1wbGVfbigxKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBsZW5ndGgodW5pcXVlX3BvcHVsYXRpb25faWQpKSAlPiUgDQogIG5yb3coLikNCg0Kbl9zcHAgPC0gRUlQQUFCX2RhdGFiYXNlICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHVuaXF1ZV9wb3B1bGF0aW9uX2lkLCBzcGVjaWVzX25jYmlfdGF4b25vbXlfaWQpICU+JSANCiAgZHBseXI6OnNhbXBsZV9uKDEpICU+JSANCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzcGVjaWVzX25hbWUsIHNwZWNpZXNfbmNiaV90YXhvbm9teV9pZCkgJT4lDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBsZW5ndGgoc3BlY2llc19uYW1lKSwNCiAgICAgICAgICAgICAgICAgcGVyY2VudCA9IHJvdW5kKG4vbl90b3RhbCoxMDAsMSkpICU+JSANCiAgZHBseXI6OmFycmFuZ2UoZGVzYyhuKSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHNwcF9udW1iZXIgPSAxOm5yb3coLikpDQoNCm5fc3BwDQpgYGANCg0KTWFraW5nIGEgYnJvYWQgY2F0ZWdvcnkgb2YgYWJ1bmRhbmNlIChhcnRpY2xlX25fZ3JvdXApIHRvIG1ha2UgdGhlIHN1bW1hcnkgYW5kIGZpZ3VyZSBtb3JlIGRpZ2VzdGlibGUgIA0KDQpgYGB7cn0NCm5fc3BwX2ZpZ19kYXRhIDwtIG5fc3BwICU+JSANCiAgZHBseXI6Om11dGF0ZShzcGVjaWVzX25jYmlfdGF4b25vbXlfaWQgPSBmY3RfcmVvcmRlcihzcGVjaWVzX25jYmlfdGF4b25vbXlfaWQsIGRlc2MobikpKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoDQogICAgYXJ0aWNsZV9uX2dyb3VwID0gY2FzZV93aGVuKA0KICAgICAgbiA9PSAxIH4gIk9uZSBvbmx5IiwNCiAgICAgIG4gPj0gMiAmIG4gPD0gNSB+ICJCZXR3ZWVuIDIgYW5kIDUiLA0KICAgICAgbiA+PSA1ICYgbiA8PSAxMCB+ICJCZXR3ZWVuIDYgYW5kIDEwIiwNCiAgICAgIG4gPj0gMTAgfiAiR3JlYXRlciB0aGFuIDEwIiwNCiAgICAgIFRSVUUgfiAiT3RoZXJzIg0KICAgICkNCiAgKQ0KYGBgDQoNCg0KVGhpcyBpcyB0aGUgbnVtYmVyIG9mIHNwZWNpZXMgaW4gZWFjaCBjYXRlZ29yeQ0KDQpgYGB7cn0NCmFydGljbGVfbl9ncm91cF9zdW1tYXJ5IDwtIG5fc3BwX2ZpZ19kYXRhICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KGFydGljbGVfbl9ncm91cCkgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuX2NhdCA9IGxlbmd0aChzcGVjaWVzX25hbWUpKQ0KYXJ0aWNsZV9uX2dyb3VwX3N1bW1hcnkNCmBgYA0KDQpNYWtpbmcgYSBwbG90IHRvIHNob3cgdGhlIGRpc3RyaWJ1dGlvbiBvZiBzcGVjaWVzIHVzZSBpbiB0aGUgRUlQQUFCIGRhdGFiYXNlDQoNCmBgYHtyLCBmaWcud2lkdGg9NSwgZmlnLmhlaWdodD01fQ0Kbl9zcHBfZmlnIDwtIG5fc3BwX2ZpZ19kYXRhICU+JSANCiAgZHBseXI6Om11dGF0ZShhcnRpY2xlX25fZ3JvdXAgPSBmY3RfcmVsZXZlbChhcnRpY2xlX25fZ3JvdXAsICJHcmVhdGVyIHRoYW4gMTAiLCAiQmV0d2VlbiA2IGFuZCAxMCIsICJCZXR3ZWVuIDIgYW5kIDUiLCAiT25lIG9ubHkiKSkgJT4lIA0KICBnZ3Bsb3QoYWVzKHkgPSBuLCB4ID0gc3BwX251bWJlciwgY29sb3IgPSBhcnRpY2xlX25fZ3JvdXApKSArDQogIGdlb21fbGluZShsaW5ld2lkdGggPSAxLCBhbHBoYSA9IDAuMikgKw0KICBnZW9tX3BvaW50KHN0YXQgPSAiaWRlbnRpdHkiLCBzaXplID0gMSwgYWxwaGEgPSAwLjgpICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKA0KICAgIHZhbHVlcyA9IGMoDQogICAgIk9uZSBvbmx5IiA9ICIjRTk0MDM5IiwgDQogICAgIkJldHdlZW4gMiBhbmQgNSIgPSAiI0YxOEU3NiIsIA0KICAgICJCZXR3ZWVuIDYgYW5kIDEwIiA9ICIjODc3RkJDIiwgDQogICAgIkdyZWF0ZXIgdGhhbiAxMCIgPSAiIzRENDc5RCINCiAgICApLA0KICBsYWJlbHMgPSBjKA0KICAgICAgIk9uZSBvbmx5IiA9ICJPbmUgb25seSAobiA9IDEwNCkiLA0KICAgICAgIkJldHdlZW4gMiBhbmQgNSIgPSAiQmV0d2VlbiAyIGFuZCA1IChuID0gNTMpIiwNCiAgICAgICJCZXR3ZWVuIDYgYW5kIDEwIiA9ICJCZXR3ZWVuIDYgYW5kIDEwIChuID0gMTEpIiwNCiAgICAgICJHcmVhdGVyIHRoYW4gMTAiID0gIkdyZWF0ZXIgdGhhbiAxMCAobiA9IDYpIg0KICAgICAgKQ0KICApICsgICMgU2V0IGNvbG91cnMgZm9yIGVhY2ggY2F0ZWdvcnkNCiAgdGhlbWVfY2xhc3NpYygpICsNCiAgdGhlbWUoDQogICAgbGVnZW5kLnBvc2l0aW9uID0gYygtMC4zLCAwLjQpLCAgIyBQb3NpdGlvbmluZyB0aGUgbGVnZW5kIGluc2lkZSB0aGUgcGxvdA0KICAgIGxlZ2VuZC5qdXN0aWZpY2F0aW9uID0gYygtMywgMCksICAgIyBCb3R0b20gbGVmdCBpbnNpZGUgdGhlIHBsb3QNCiAgICBsZWdlbmQuYm94Lmp1c3QgPSAicmlnaHQiDQogICAgKSArDQogIGxhYnMoDQogICAgeCA9IHBhc3RlMCgiU3BlY2llcyAoMS0xNzQpIiksDQogICAgeSA9ICJOdW1iZXIgb2YgYXJ0aWNsZXMiLA0KICAgIGNvbG9yID0gIkFydGljbGUgbnVtYmVyIGNhdGVnb3J5Ig0KICApDQoNCm5fc3BwX2ZpZw0KYGBgDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQ0Kc2V0d2QoZmlndXJlc19wYXRoKQ0KZ2dzYXZlKCJzcHBfbl9zcHBfZmlnLnBkZiIsIHBsb3QgPSBuX3NwcF9maWcsIHdpZHRoID0gNSwgaGVpZ2h0ID0gNSkNCmBgYA0KDQpNYWtpbmcgYSBsaXN0IG9mIHRoZSBtb3N0IGNvbW1vbiAxNSBzcGVjaWVzDQoNCmBgYHtyfQ0Kbl9zcHBfdXNlZCA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lIA0KICBkcGx5cjo6ZGlzdGluY3QodW5pcXVlX3BvcHVsYXRpb25faWQpICU+JSANCiAgbnJvdyguKQ0KDQp0b3BfMTVfc3BwX2xpc3QgPC0gRUlQQUFCX2RhdGFiYXNlICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHNwZWNpZXNfbmFtZSkgJT4lIA0KICBkcGx5cjo6c3VtbWFyaXNlKG4gPSBsZW5ndGgodW5pcXVlKHVuaXF1ZV9wb3B1bGF0aW9uX2lkKSksIC5ncm91cHMgPSAnZHJvcCcpICU+JSANCiAgZHBseXI6OmFycmFuZ2UoZGVzYyhuKSkgJT4lICANCiAgZHBseXI6OnNsaWNlKDE6MTUpICU+JSANCiAgZHBseXI6OnB1bGwoc3BlY2llc19uYW1lKSAlPiUgDQogIGFzLmxpc3QoKQ0KYGBgDQoNCk1ha2luZyBhIHN1bW1hcnkgZGF0YWZyYW1lIGJhc2Ugb24gc3R1ZHkgbW90aXZhdGlvbg0KDQpgYGB7cn0NCmNvbW1vbl9zcGVjaWVzIDwtIEVJUEFBQl9kYXRhYmFzZSAlPiUNCiAgZHBseXI6OmZpbHRlcihzcGVjaWVzX25hbWUgJWluJSB0b3BfMTVfc3BwX2xpc3QpICU+JQ0KICBkcGx5cjo6Z3JvdXBfYnkoc3BlY2llc19uYW1lLCBzdHVkeV9tb3RpdmF0aW9uKSAlPiUNCiAgZHBseXI6OnN1bW1hcmlzZShuID0gbGVuZ3RoKHVuaXF1ZShhcnRpY2xlX2lkKSksIC5ncm91cHMgPSAnZHJvcCcpICU+JQ0KICB0aWR5cjo6Y29tcGxldGUoc3BlY2llc19uYW1lLCBzdHVkeV9tb3RpdmF0aW9uLCBmaWxsID0gbGlzdChuID0gMCkpDQoNCg0Kc3BlY2llc19vcmRlciA8LSBjb21tb25fc3BlY2llcyAlPiUNCiAgZ3JvdXBfYnkoc3BlY2llc19uYW1lKSAlPiUNCiAgc3VtbWFyaXNlKHRvdGFsX24gPSBzdW0obiksIC5ncm91cHMgPSAnZHJvcCcpICU+JQ0KICBhcnJhbmdlKGRlc2ModG90YWxfbikpICU+JQ0KICB1bmdyb3VwKCkNCg0KDQpjb21tb25fc3BlY2llcyA8LSBjb21tb25fc3BlY2llcyAlPiUNCiAgaW5uZXJfam9pbihzcGVjaWVzX29yZGVyLCBieSA9ICJzcGVjaWVzX25hbWUiKSAlPiUNCiAgbXV0YXRlKHNwZWNpZXNfbmFtZSA9IGZjdF9yZW9yZGVyKHNwZWNpZXNfbmFtZSwgdG90YWxfbiksDQogICAgICAgICBzdHVkeV9tb3RpdmF0aW9uID0gZmN0X3JlbGV2ZWwoc3R1ZHlfbW90aXZhdGlvbiwgIkVudmlyb25tZW50YWwiLCAiTWVkaWNhbCIsICJCYXNpYyByZXNlYXJjaCIpKSANCmBgYA0KDQpBIHBsb3Qgb2YgdGhlIG51bWJlciBvZiB0aW1lcyBlYWNoIG9mIHRoZSAxNSBvdmVyYWxsIG1vc3QgY29tbW9uIHNwZWNpZXMgYXBwZWFyZWQgaW4gYXJ0aWNsZXMgd2l0aGluIHRoZSBFSVBBQUIgZGF0YWJzZSBieSBzdHVkeSBtb3RpdmF0aW9uLiBJdCdzIGEgbGl0dGxlIGhhcmQgdG8gc2VlIGluIHRoZSBjaHVuayBvdXRwdXQsIHRyeSB2aWV3aW5nIGluIGFuIGV4dGVybmFsIHdpbmRvdy4gDQoNCmBgYHtyLCBmaWcuaGVpZ2h0PTEwLCBmaWcud2lkdGg9NX0NCnRvcF8xNV9zcHBfZmlnIDwtIGNvbW1vbl9zcGVjaWVzICU+JSANCiAgZ2dwbG90KGFlcyh4PXNwZWNpZXNfbmFtZSwgeT1uLCBjb2xvdXIgPSBzdHVkeV9tb3RpdmF0aW9uLCBmaWxsID0gc3R1ZHlfbW90aXZhdGlvbiwgZ3JvdXAgPSBzdHVkeV9tb3RpdmF0aW9uKSkgKw0KICBnZW9tX2NvbChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC44KSwgd2lkdGggPSAwLjEpICsNCiAgZ2VvbV9wb2ludChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC44KSwgc2l6ZSA9IDMpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IG4pLCBoanVzdD0tMC42LCBzaXplPTMuNSwgY29sb3I9ImJsYWNrIiwgcG9zaXRpb24gPSAgcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjgpKSArDQogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gbW90aXZhdGlvbl9jb2xvdXJfdGhlbWUsIG5hbWUgPSAiU3R1ZHkgbW90aXZhdGlvbiIpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gbW90aXZhdGlvbl9jb2xvdXJfdGhlbWUsIG5hbWUgPSAiU3R1ZHkgbW90aXZhdGlvbiIpICsNCiAgY29vcmRfZmxpcCgpICsNCiAgdGhlbWVfY2xhc3NpYygpICsNCiAgIGxhYnMoDQogICAgeCA9ICIiLA0KICAgIHkgPSAiTnVtYmVyIG9mIHN0dWRpZXMiDQogICkgKw0KICAgdGhlbWUoKQ0KDQp0b3BfMTVfc3BwX2ZpZw0KYGBgDQoNCg0KYGBge3IsIHdhcm5pbmc9RkFMU0V9DQpzZXR3ZChmaWd1cmVzX3BhdGgpDQpnZ3NhdmUoInNwcF90b3BfMTVfc3BwX2ZpZy5wZGYiLCBwbG90ID0gdG9wXzE1X3NwcF9maWcsIHdpZHRoID0gNSwgaGVpZ2h0ID0gMTApDQpgYGANCg0KDQpTdW1tYXJpc2luZyB0aGUgdG9wIDEwIGluIGVhY2ggbW90aXZhdGlvbiBtb3JlIHNwZWNpZmljYWxseQ0KDQpgYGB7cn0NCnNwcF9tb2l0aXZhdGlvbl9zdW1tYXJ5IDwtIEVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzcGVjaWVzX25hbWUsIHN0dWR5X21vdGl2YXRpb24pICU+JSANCiAgZHBseXI6OnN1bW1hcmlzZShuID0gbGVuZ3RoKHVuaXF1ZSh1bmlxdWVfcG9wdWxhdGlvbl9pZCkpLCAuZ3JvdXBzID0gJ2Ryb3AnKSAlPiUgDQogIHRpZHlyOjpjb21wbGV0ZShzcGVjaWVzX25hbWUsIHN0dWR5X21vdGl2YXRpb24sIGZpbGwgPSBsaXN0KG4gPSAwKSkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHRvdGFsID0gc3VtKG4pKSAlPiUgDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHByb3AgPSBuL3RvdGFsKSAlPiUgDQogIGRwbHlyOjpzZWxlY3QoLXRvdGFsKQ0KYGBgDQoNClRoaXMgcGxvdCBzaG93cyB0aGUgdG9wIDEwIGluIGVhY2ggbW90aXZhdGlvbg0KDQpgYGB7cn0NCnRvcF8xMF9lbnZfc3BwIDwtIHNwcF9tb2l0aXZhdGlvbl9zdW1tYXJ5ICU+JSANCiAgZHBseXI6OmZpbHRlcihzdHVkeV9tb3RpdmF0aW9uID09ICJFbnZpcm9ubWVudGFsIikgJT4lIA0KICBkcGx5cjo6YXJyYW5nZShkZXNjKG4pKSAlPiUgDQogIGRwbHlyOjpzbGljZSgxOjEwKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoc3BlY2llc19uYW1lID0gZmN0X3Jlb3JkZXIoc3BlY2llc19uYW1lLCBuKSkgJT4lIA0KICBnZ3Bsb3QoYWVzKHg9c3BlY2llc19uYW1lLCB5PW4pKSArDQogIGdlb21fY29sKHdpZHRoID0gMC4wMSwgY29sb3VyID0gIiM2MEJENkMiLCBmaWxsID0gIiM2MEJENkMiKSArDQogIGdlb21fcG9pbnQoc2l6ZSA9IDIsIGNvbG91ciA9ICIjNjBCRDZDIiwgZmlsbCA9ICIjNjBCRDZDIikgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gbiksIGhqdXN0PS0wLjYsIHNpemU9My41LCBjb2xvcj0iYmxhY2siKSArDQogIGNvb3JkX2ZsaXAoKSArDQogIHRoZW1lX2NsYXNzaWMoKSArDQogICBsYWJzKA0KICAgIHggPSAiIiwNCiAgICB5ID0gIk51bWJlciBvZiBzdHVkaWVzIiwNCiAgICB0aXRsZSA9ICJFbnZpcm9ubWVudGFsIg0KICApICsNCiAgIHRoZW1lKA0KICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMikNCiAgICkNCg0KdG9wXzEwX21lZF9zcHAgPC0gc3BwX21vaXRpdmF0aW9uX3N1bW1hcnkgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKHN0dWR5X21vdGl2YXRpb24gPT0gIk1lZGljYWwiKSAlPiUgDQogIGRwbHlyOjphcnJhbmdlKGRlc2MobikpICU+JSANCiAgZHBseXI6OnNsaWNlKDE6MTApICU+JSANCiAgZHBseXI6Om11dGF0ZShzcGVjaWVzX25hbWUgPSBmY3RfcmVvcmRlcihzcGVjaWVzX25hbWUsIG4pKSAlPiUgDQogIGdncGxvdChhZXMoeD1zcGVjaWVzX25hbWUsIHk9bikpICsNCiAgZ2VvbV9jb2wod2lkdGggPSAwLjAxLCBjb2xvdXIgPSAiI0QzNTlBMSIsIGZpbGwgPSAiI0QzNTlBMSIpICsNCiAgZ2VvbV9wb2ludChzaXplID0gMiwgY29sb3VyID0gIiNEMzU5QTEiLCBmaWxsID0gIiNEMzU5QTEiKSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBuKSwgaGp1c3Q9LTAuNiwgc2l6ZT0zLjUsIGNvbG9yPSJibGFjayIpICsNCiAgY29vcmRfZmxpcCgpICsNCiAgdGhlbWVfY2xhc3NpYygpICsNCiAgIGxhYnMoDQogICAgeCA9ICIiLA0KICAgIHkgPSAiTnVtYmVyIG9mIHN0dWRpZXMiLA0KICAgIHRpdGxlID0gIk1lZGljYWwiDQogICkgKw0KICAgdGhlbWUoDQogICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKQ0KICAgKQ0KDQp0b3BfMTBfYmFzZV9zcHAgPC0gc3BwX21vaXRpdmF0aW9uX3N1bW1hcnkgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKHN0dWR5X21vdGl2YXRpb24gPT0gIkJhc2ljIHJlc2VhcmNoIikgJT4lIA0KICBkcGx5cjo6YXJyYW5nZShkZXNjKG4pKSAlPiUgDQogIGRwbHlyOjpzbGljZSgxOjEwKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoc3BlY2llc19uYW1lID0gZmN0X3Jlb3JkZXIoc3BlY2llc19uYW1lLCBuKSkgJT4lIA0KICBnZ3Bsb3QoYWVzKHg9c3BlY2llc19uYW1lLCB5PW4pKSArDQogIGdlb21fY29sKHdpZHRoID0gMC4wMSwgY29sb3VyID0gIiMzQzgyQzQiLCBmaWxsID0gIiMzQzgyQzQiKSArDQogIGdlb21fcG9pbnQoc2l6ZSA9IDIsIGNvbG91ciA9ICIjM0M4MkM0IiwgZmlsbCA9ICIjM0M4MkM0IikgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gbiksIGhqdXN0PS0wLjYsIHNpemU9My41LCBjb2xvcj0iYmxhY2siKSArDQogIGNvb3JkX2ZsaXAoKSArDQogIHRoZW1lX2NsYXNzaWMoKSArDQogICBsYWJzKA0KICAgIHggPSAiIiwNCiAgICB5ID0gIk51bWJlciBvZiBzdHVkaWVzIiwNCiAgICB0aXRsZSA9ICJCYXNpYyINCiAgKSArDQogICB0aGVtZSgNCiAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpDQogICApDQpgYGANCg0KSGVyZSdzIGEgcGxvdCB0byBjb21wYXJlIHRoZSB0b3AgMTAgc3BwIGluIGVhY2ggc3R1ZHkgbW90aXZhdGlvbiBtb3JlIHNwZWNpZmljYWxseSANCg0KYGBge3IgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9OH0NCnRvcF8xMF9jb21iaW5kX3Bsb3QgPC0gZ3JpZC5hcnJhbmdlKHRvcF8xMF9lbnZfc3BwLCB0b3BfMTBfbWVkX3NwcCwgdG9wXzEwX2Jhc2Vfc3BwLCBuY29sID0gMykNCmBgYA0KDQpMb29raW5nIGF0IHRoZSBudW1iZXIgb2YgZGlzdGluY3Qgc3BlY2llcyB1c2VkIGluIGVhY2ggbW90aXZhdGlvbiBncm91cA0KDQpgYGB7cn0NCkVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG5fbW90aXZhdGlvbiA9IG5fZGlzdGluY3QoYXJ0aWNsZV9pZCksDQogICAgICAgICAgICAgICAgIG5fZGlzdGluY3Rfc3BwID0gbl9kaXN0aW5jdChzcGVjaWVzX25hbWUpKQ0KYGBgDQoNCg0KIyMgMTIuNCBTcGVjaWVzIGhhYml0YXQNCg0KRmlyc3QgY2hlY2tpbmcgaG93IG1hbnkgc3BlY2llcyBoYXZlIElVQ04gZGF0YSwgd2hpY2ggd2Ugd2lsbCB1c2UgdG8gYXNzZXNzIGhhYml0YXQgZGlmZmVyZW5jZXMNCg0KYGBge3J9DQpzcGVjaWVzX2l1Y25fc3VtbWFyeSA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3BlY2llc19uYW1lKSAlPiUgDQogIGRwbHlyOjpzYW1wbGVfbigxKSAlPiUgDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHNwZWNpZXNfaXVjbl9iaW4gPSBpZl9lbHNlKGlzLm5hKHNwZWNpZXNfaXVjbl9kb2kpLCAiTm8iLCAiWWVzIikpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHNwZWNpZXNfaXVjbl9iaW4pICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IGxlbmd0aChzcGVjaWVzX2l1Y25fYmluKSkNCg0Kc3BlY2llc19pdWNuX3N1bW1hcnkNCmBgYA0KDQpTdW1tYXJpc2luZyB0aGUgSVVOQyBoYWJpdGF0IHR5cGUsIHNvbWUgc3BlY2llcyB3aWxsIGhhdmUgbXVsdGlwbGUgaGFiaXRhdHMsIHNvIHdlIHNwbGl0IHRoZSBzdHJpbmcgYnkgdGhlIHNlcHJlYXRlICg7KQ0KDQpgYGB7cn0NCmhhYml0YXRfc3VtbWFyeSA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkodW5pcXVlX3BvcHVsYXRpb25faWQpICU+JSANCiAgZHBseXI6OnNhbXBsZV9uKDEpICU+JSAjIHNhbXBsaW5nIG9uZSByb3cgcGVyIGFydGljbGUgcGVyIHNwZWNpZXMgKGkuZS4gaWdub3JpbmcgbXVsdGlwbGUgcm93cyBwZXIgYXJ0aWNsZSBmb3IgY29tcG91bmRzKQ0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHNwZWNpZXNfaXVjbl9oYWJpdGF0KSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBuKCkpICU+JQ0KICBkcGx5cjo6bXV0YXRlKHNwZWNpZXNfaXVjbl9oYWJpdGF0ID0gc3RyX3RyaW0oc3BlY2llc19pdWNuX2hhYml0YXQpKSAlPiUNCiAgdGlkeXI6OnNlcGFyYXRlX3Jvd3Moc3BlY2llc19pdWNuX2hhYml0YXQsIHNlcCA9ICI7IikgJT4lICMgZWFjaCBzcHAgaGFzIG11bHRpcGxlIGhhYml0YXRzIHRoZSBzdHJpbmcgbmVlZHMgc3BsaXRpbmcNCiAgZHBseXI6Omdyb3VwX2J5KHNwZWNpZXNfaXVjbl9oYWJpdGF0KSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG5fYXJ0aWNsZXMgPSBzdW0obikpICU+JSAjIG5vdyBhIHN1bSBmb3IgZWFjaCBoYWJpdGF0DQogIGFycmFuZ2UoZGVzYyhuX2FydGljbGVzKSkNCmhhYml0YXRfc3VtbWFyeQ0KYGBgDQoNCkNoZWNraW5nIGhvdyBtYW55IGZyZXNod2F0ZXIgdnMgbWFyaW5lIHNwZWNpZXMgdGhlcmUgYXJlLiBXZXRsYW5kcyBpbmxhbmQgY2F0ZWdvcmllcyBhcmUgZnJlc2h3YXRlciBib2RpZXMgd2hlcmUgYXMgTWFyaW5lICBoYXZlIG11bHRpcGxlIGNhdGVnb3JpZXMgKE1hcmluZSBOZXJpdGljLCBNYXJpbmUgQ29hc3RhbCBvciBTdXByYXRpZGFsLCBNYXJpbmUgSW50ZXJ0aWRhbCwgTWFyaW5lIE9jZWFuaWMpLiANCg0KYGBge3J9DQpoYWJpdGF0X3N1bW1hcnkgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKHN0cl9zdGFydHMoc3BlY2llc19pdWNuX2hhYml0YXQsICJNYXJpbmUiKSB8IHNwZWNpZXNfaXVjbl9oYWJpdGF0ID09ICJXZXRsYW5kcyBpbmxhbmQiKSAlPiUgIyBPbmx5IGhhYml0YXRzIG9mIGludGVyZXN0IA0KICBkcGx5cjo6bXV0YXRlKGFxdWF0aWNfdHlwZSA9IGlmX2Vsc2Uoc3BlY2llc19pdWNuX2hhYml0YXQgPT0gIldldGxhbmRzIGlubGFuZCIsICJGcmVzaHdhdGVyIiwgIk1hcmluZSIpKSAlPiUgIyBOZXcgY2F0ZWdvcnkNCiAgZHBseXI6Omdyb3VwX2J5KGFxdWF0aWNfdHlwZSkgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuX2FydGljbGVzID0gc3VtKG5fYXJ0aWNsZXMpKSAlPiUgIyBGaW5hbCBzdW1zDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKG5fdG90YWwgPSBzdW0obl9hcnRpY2xlcyksDQogICAgICAgICAgICAgICAgcGVyY2VudCA9ICByb3VuZChuX2FydGljbGVzL25fdG90YWwqMTAwLDEpKQ0KYGBgDQoNCg0KTGV0cyBicmVhayB0aGlzIHVwIGJ5IHN0dWR5IG1vdGl2YXRpb24gDQoNCmBgYHtyfQ0KaGFiaXRhdF9zdW1tYXJ5X2FsbCA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkodW5pcXVlX3BvcHVsYXRpb25faWQpICU+JSANCiAgZHBseXI6OnNhbXBsZV9uKDEpICU+JSAjIHNhbXBsaW5nIG9uZSByb3cgcGVyIGFydGljbGUgcGVyIHNwZWNpZXMgKGkuZS4gaWdub3JpbmcgbXVsdGlwbGUgcm93cyBwZXIgYXJ0aWNsZSBmb3IgY29tcG91bmRzKQ0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHN0dWR5X21vdGl2YXRpb24sIHNwZWNpZXNfaXVjbl9oYWJpdGF0KSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBuKCkpICU+JQ0KICBkcGx5cjo6bXV0YXRlKHNwZWNpZXNfaXVjbl9oYWJpdGF0ID0gc3RyX3RyaW0oc3BlY2llc19pdWNuX2hhYml0YXQpKSAlPiUNCiAgdGlkeXI6OnNlcGFyYXRlX3Jvd3Moc3BlY2llc19pdWNuX2hhYml0YXQsIHNlcCA9ICI7IikgJT4lICMgZWFjaCBzcHAgaGFzIG11bHRpcGxlIGhhYml0YXRzIHRoZSBzdHJpbmcgbmVlZHMgc3BsaXRpbmcNCiAgZHBseXI6Omdyb3VwX2J5KHNwZWNpZXNfaXVjbl9oYWJpdGF0LCBzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG5fYXJ0aWNsZXMgPSBzdW0obikpICU+JSAjIG5vdyBhIHN1bSBmb3IgZWFjaCBoYWJpdGF0DQogIGFycmFuZ2UoZGVzYyhuX2FydGljbGVzKSkNCmhhYml0YXRfc3VtbWFyeV9hbGwNCmBgYA0KDQpTZWxlY3Rpbmcgb25seSBoYWJpdGF0cyBvZiBpbnRlcmVzdCBhbmQgYWxsb2NhdGluZyB0byBGcmVzaHdhdGVyIG9yIE1hcmluZQ0KDQpgYGB7cn0NCmZyZXNod2F0ZXJfbWFyaW5lIDwtIGhhYml0YXRfc3VtbWFyeV9hbGwgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKHN0cl9zdGFydHMoc3BlY2llc19pdWNuX2hhYml0YXQsICJNYXJpbmUiKSB8IHNwZWNpZXNfaXVjbl9oYWJpdGF0ID09ICJXZXRsYW5kcyBpbmxhbmQiKSAlPiUgIyBPbmx5IGhhYml0YXRzIG9mIGludGVyZXN0IA0KICBkcGx5cjo6bXV0YXRlKGFxdWF0aWNfdHlwZSA9IGlmX2Vsc2Uoc3BlY2llc19pdWNuX2hhYml0YXQgPT0gIldldGxhbmRzIGlubGFuZCIsICJGcmVzaHdhdGVyIiwgIk1hcmluZSIpKSAlPiUgIyBOZXcgY2F0ZWdvcnkNCiAgZHBseXI6Omdyb3VwX2J5KGFxdWF0aWNfdHlwZSwgc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuX2FydGljbGVzID0gc3VtKG5fYXJ0aWNsZXMpKSAlPiUgIyBGaW5hbCBzdW1zDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIGRwbHlyOjptdXRhdGUobl9jYXQgPSBzdW0obl9hcnRpY2xlcykpICU+JSANCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjptdXRhdGUocHJvcCA9ICBuX2FydGljbGVzL25fY2F0KSAjIEEgcHJvcG9ydGlvbiBvZiB0aG9zZSBpZGVudGlmeSBhcyBmcmVzaHdhdGVyIHZzIG1hcmluZQ0KDQpmcmVzaHdhdGVyX21hcmluZQ0KYGBgDQoNCg0KYGBge3IsIGZpZy53aWR0aD01LCBmaWcuaGVpZ2h0PTIuNX0NCmFxdWF0aWNfdHlwZV9vcmRlciA8LSBjKCJGcmVzaHdhdGVyIiwgIk1hcmluZSIpDQoNCiMgRGVmaW5lIHRoZSBibGFjayBhbmQgZ3JleSBjb2xvciB0aGVtZQ0KI2NvbG9yX3RoZW1lIDwtIGMoIiM3RkFCOTEiLCAiIzJBNEE2NCIpDQoNCiMgQ2FsY3VsYXRlIGN1bXVsYXRpdmUgcG9zaXRpb25zIGZvciB0ZXh0IGxhYmVscw0KZnJlc2h3YXRlcl9tYXJpbmUgPC0gZnJlc2h3YXRlcl9tYXJpbmUgJT4lDQogIGRwbHlyOjptdXRhdGUoYXF1YXRpY190eXBlID0gZmFjdG9yKGFxdWF0aWNfdHlwZSwgbGV2ZWxzID0gYXF1YXRpY190eXBlX29yZGVyKSkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3R1ZHlfbW90aXZhdGlvbikgJT4lDQogIGRwbHlyOjphcnJhbmdlKGRlc2MoYXF1YXRpY190eXBlKSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKGN1bXVsYXRpdmVfcHJvcCA9IGN1bXN1bShwcm9wKSAtIHByb3AgLyAyKQ0KDQojIERlZmluZSB0aGUgYmxhY2sgYW5kIGdyZXkgY29sb3IgdGhlbWUNCmNvbG9yX3RoZW1lIDwtIGMoIiM3RkFCOTEiLCAiIzJBNEE2NCIpDQoNCiMgQ3JlYXRlIHRoZSBwbG90DQpoYWJpdGF0X2ZpZyA8LSBmcmVzaHdhdGVyX21hcmluZSAlPiUNCiAgbXV0YXRlKHN0dWR5X21vdGl2YXRpb24gPSBmY3RfcmVsZXZlbChzdHVkeV9tb3RpdmF0aW9uLCAiQmFzaWMgcmVzZWFyY2giLCAiTWVkaWNhbCIsICJFbnZpcm9ubWVudGFsIikpICU+JSANCiAgZ2dwbG90KGFlcyh5ID0gcHJvcCwgeCA9IHN0dWR5X21vdGl2YXRpb24sIGZpbGwgPSBhcXVhdGljX3R5cGUsIGdyb3VwID0gYXF1YXRpY190eXBlKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5Iiwgd2lkdGggPSAwLjkpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHJvdW5kKHByb3AsIDIpLCB5ID0gY3VtdWxhdGl2ZV9wcm9wKSwgY29sb3IgPSAid2hpdGUiLCBzaXplID0gMykgKyANCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sb3JfdGhlbWUsIG5hbWUgPSAiSGFiaXRhdCIpICsgDQogIHRoZW1lX2NsYXNzaWMoKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIpICsNCiAgbGFicygNCiAgICB4ID0gIlN0dWR5IG1vdGl2YXRpb24iLA0KICAgIHkgPSAiUHJvcG9ydGlvbiBvZiBhbGwgc3BlY2llcyBhc3NpZ25lZCB0byBmcmVzaHdhdGVyIG9yIG1hcmluZSBoYWJpdGF0Ig0KICApICsNCiAgY29vcmRfZmxpcCgpDQoNCmhhYml0YXRfZmlnDQpgYGANCg0KDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCnNldHdkKGZpZ3VyZXNfcGF0aCkNCmdnc2F2ZSgic3BwX2hhYml0YXRfZmlnLnBkZiIsIHBsb3QgPSBoYWJpdGF0X2ZpZywgd2lkdGggPSAxMCwgaGVpZ2h0ID0gNSkNCmBgYA0KDQpXZSBzaG91bGQgYWxzbyBjb25zaWRlciBob3cgbWFueSByZWNvcmRzIGRpZCBub3QgaW5jdWxkZSBJVUNOIHJlcG9ydHMgYW5kIHRodXMgaGFiaXRhdC4NCg0KTGV0J3MgbWFrZSBhIHBsb3QgdGhhdCBzaG93cyBob3cgbWFueSBkaWRuJ3QgaGF2ZSBhbiBhc3NpZ25lZCBJVU5DIGhhYml0YXQuIFRvIGFkZCB0byB0aGUgYWJvdmUgZmlndXJlLg0KDQpgYGB7cn0NCm5vX2hhYml0YXQgPC0gRUlQQUFCX2RhdGFiYXNlICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHVuaXF1ZV9wb3B1bGF0aW9uX2lkKSAlPiUgDQogIGRwbHlyOjpzYW1wbGVfbigxKSAlPiUgIyBzYW1wbGluZyBvbmUgcm93IHBlciBhcnRpY2xlIHBlciBzcGVjaWVzIChpLmUuIGlnbm9yaW5nIG11bHRpcGxlIHJvd3MgcGVyIGFydGljbGUgZm9yIGNvbXBvdW5kcykNCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUNCiAgZHBseXI6Om11dGF0ZShzcGVjaWVzX2l1Y25fYmluID0gaWZfZWxzZShpcy5uYShzcGVjaWVzX2l1Y25fZG9pKSwgIk5vIiwgIlllcyIpKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzcGVjaWVzX2l1Y25fYmluKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBsZW5ndGgoc3BlY2llc19pdWNuX2JpbikpDQogIA0KDQpuX3RvdGFsIDwtIEVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIGRwbHlyOjpncm91cF9ieSh1bmlxdWVfcG9wdWxhdGlvbl9pZCkgJT4lIA0KICBkcGx5cjo6c2FtcGxlX24oMSkgJT4lICMgc2FtcGxpbmcgb25lIHJvdyBwZXIgYXJ0aWNsZSBwZXIgc3BlY2llcyAoaS5lLiBpZ25vcmluZyBtdWx0aXBsZSByb3dzIHBlciBhcnRpY2xlIGZvciBjb21wb3VuZHMpDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lDQogIG5yb3coLikNCg0Kbm9faGFiaXRhdCA8LSBub19oYWJpdGF0ICU+JQ0KICBkcGx5cjo6bXV0YXRlKHByb3AgPSBuL25fdG90YWwpDQoNCm5vX2hhYml0YXQNCmBgYA0KDQpIZXJlJ3MgdGhlIHBsb3QgDQoNCmBgYHtyLCBmaWcud2lkdGg9Mi41LCBmaWcuaGVpZ2h0PTV9DQojIERlZmluZSB0aGUgYmxhY2sgYW5kIGdyZXkgY29sb3IgdGhlbWUNCmJsYWNrX2FuZF9ncmV5IDwtIGMoIiNCQ0JFQzAiLCAiIzQxNDA0MiIpDQoNCnllc19vcmRlciA8LSBjKCJZZXMiLCAiTm8iKQ0KDQojIENhbGN1bGF0ZSBjdW11bGF0aXZlIHBvc2l0aW9ucyBmb3IgdGV4dCBsYWJlbHMNCmhhYml0YXRfaW5mb19kZl9maWcgPC0gbm9faGFiaXRhdCAlPiUNCiAgZHBseXI6Om11dGF0ZShzcGVjaWVzX2l1Y25fYmluID0gZmFjdG9yKHNwZWNpZXNfaXVjbl9iaW4sIGxldmVscyA9IHllc19vcmRlcikpICU+JSANCiAgZHBseXI6OmFycmFuZ2UoZGVzYyhzcGVjaWVzX2l1Y25fYmluKSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKGN1bXVsYXRpdmVfcHJvcCA9IGN1bXN1bShwcm9wKSAtIHByb3AgLyAyKQ0KDQpoYWJpdGF0X2luZm9fZmlnIDwtIGhhYml0YXRfaW5mb19kZl9maWcgJT4lDQogIGRwbHlyOjptdXRhdGUoc3BlY2llc19pdWNuX2JpbiA9IGZhY3RvcihzcGVjaWVzX2l1Y25fYmluLCBsZXZlbHMgPSB5ZXNfb3JkZXIpKSAlPiUgDQogIGdncGxvdChhZXMoeSA9IHByb3AsIHggPSAxLCBmaWxsID0gc3BlY2llc19pdWNuX2JpbikpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHdpZHRoID0gMC4xKSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSByb3VuZChwcm9wLCAyKSwgeSA9IGN1bXVsYXRpdmVfcHJvcCksIGNvbG9yID0gIndoaXRlIikgKyANCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYmxhY2tfYW5kX2dyZXksIG5hbWUgPSAiSGFiaXRhdCIpICsgDQogIHRoZW1lX2NsYXNzaWMoKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsDQogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLCAgIyBSZW1vdmUgeC1heGlzIHRleHQNCiAgICAgICAgYXhpcy50aWNrcy54ID0gZWxlbWVudF9ibGFuaygpICAjIFJlbW92ZSB4LWF4aXMgdGlja3MgDQogICAgICAgICkgKw0KICBsYWJzKA0KICAgIHggPSAiIiwNCiAgICB5ID0gIlByb3BvcnRpb24gb2Ygc3BlY2llcyB0ZXN0ZWQgaW4gdGhlIGRhdGFiYXNlIg0KICApDQpoYWJpdGF0X2luZm9fZmlnDQpgYGANCg0KYGBge3IsIHdhcm5pbmc9RkFMU0V9DQpzZXR3ZChmaWd1cmVzX3BhdGgpDQpnZ3NhdmUoInNwcF9oYWJpdGF0X2luZm9fZmlnLnBkZiIsIHBsb3QgPSBoYWJpdGF0X2luZm9fZmlnLCB3aWR0aCA9IDUsIGhlaWdodCA9IDEwKQ0KYGBgDQoNCg0KIyMgMTIuNSBTcGVjaWVzIGxpZmUgc2F0Z2UgDQoNCkxldCdzIGdldCBhbiBvdmVyYWxsIHN1bW1hcnkgZmlyc3QsIHdpdGhvdXQgVW5rbm93biBvciBub3Qgc3BlY2lmaWVkIGxpZmUgc3RhZ2VzDQoNCmBgYHtyfQ0KRUlQQUFCX2RhdGFiYXNlICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHVuaXF1ZV9wb3B1bGF0aW9uX2lkKSAlPiUgDQogIGRwbHlyOjpzYW1wbGVfbigxKSAlPiUgIyBzYW1wbGluZyBvbmUgcm93IHBlciBhcnRpY2xlIHBlciBzcGVjaWVzIChpLmUuIGlnbm9yaW5nIG11bHRpcGxlIHJvd3MgcGVyIGFydGljbGUgZm9yIGNvbXBvdW5kcykNCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzcGVjaWVzX3N0YWdlKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBuKCkpICU+JQ0KICBkcGx5cjo6bXV0YXRlKHNwZWNpZXNfc3RhZ2UgPSBzdHJfdHJpbShzcGVjaWVzX3N0YWdlKSkgJT4lDQogIHRpZHlyOjpzZXBhcmF0ZV9yb3dzKHNwZWNpZXNfc3RhZ2UsIHNlcCA9ICI7IikgJT4lICMgZWFjaCBzcHAgaGFzIG11bHRpcGxlIGhhYml0YXRzIHRoZSBzdHJpbmcgbmVlZHMgc3BsaXR0aW5nDQogIGRwbHlyOjpmaWx0ZXIoc3BlY2llc19zdGFnZSAhPSAiVW5rbm93biBvciBub3Qgc3BlY2lmaWVkIikgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3BlY2llc19zdGFnZSkgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuX2FydGljbGVzID0gc3VtKG4pKSAlPiUgICMgbm93IGEgc3VtIGZvciBlYWNoIGhhYml0YXQNCiAgZHBseXI6Om11dGF0ZSh0b3RhbF9zdGFnZXMgPSBzdW0obl9hcnRpY2xlcykpICU+JSANCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjptdXRhdGUob3ZlcmFsbF9wZXJjZW50ID0gcm91bmQobl9hcnRpY2xlcy90b3RhbF9zdGFnZXMqMTAwLDEpKQ0KYGBgDQoNCg0KTGV0J3MgdGFrZSBhIGxvb2sgYXQgc3BwIGxpZmUgc3RhZ2VzIHVzZWQgaW4gdGhlIEVJUEFBQiBkYXRhYmFzZWJhc2VkIG9uIHN0dWR5IG1vdGl2YXRpb24NCg0KYGBge3J9DQpzdGFnZV9zdW1tYXJ5X2FsbCA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkodW5pcXVlX3BvcHVsYXRpb25faWQpICU+JSANCiAgZHBseXI6OnNhbXBsZV9uKDEpICU+JSAjIHNhbXBsaW5nIG9uZSByb3cgcGVyIGFydGljbGUgcGVyIHNwZWNpZXMgKGkuZS4gaWdub3JpbmcgbXVsdGlwbGUgcm93cyBwZXIgYXJ0aWNsZSBmb3IgY29tcG91bmRzKQ0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHN0dWR5X21vdGl2YXRpb24sIHNwZWNpZXNfc3RhZ2UpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IG4oKSkgJT4lDQogIGRwbHlyOjptdXRhdGUoc3BlY2llc19zdGFnZSA9IHN0cl90cmltKHNwZWNpZXNfc3RhZ2UpKSAlPiUNCiAgdGlkeXI6OnNlcGFyYXRlX3Jvd3Moc3BlY2llc19zdGFnZSwgc2VwID0gIjsiKSAlPiUgIyBlYWNoIHNwcCBoYXMgbXVsdGlwbGUgaGFiaXRhdHMgdGhlIHN0cmluZyBuZWVkcyBzcGxpdHRpbmcNCiAgZHBseXI6Omdyb3VwX2J5KHNwZWNpZXNfc3RhZ2UsIHN0dWR5X21vdGl2YXRpb24pICU+JSANCiAgZHBseXI6OnJlZnJhbWUobl90b3RhbCA9IHN1bShuKSkgJT4lICAjIG5vdyBhIHN1bSBmb3IgZWFjaCBoYWJpdGF0DQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIGRwbHlyOjptdXRhdGUobl9tb3RpdmF0aW9uID0gc3VtKG5fdG90YWwpKSAlPiUgDQogIGRwbHlyOjp1bmdyb3VwKCkNCg0Kc3RhZ2Vfc3VtbWFyeV9hbGwNCmBgYA0KDQpGb3IgbGlmZSBzdGFnZXMgdGhhdCBhcmUgZGVzY3JpYmVkLCB3aGF0IGlzIHRoZSBicmVha2Rvd24gDQoNCmBgYHtyLCBmaWcud2lkdGg9NSwgZmlnLmhlaWdodD0yLjV9DQpzdGFnZV9vcmRlciA8LSBjKCJBZHVsdCIsICJKdXZlbmlsZSIsICJMYXJ2YWUiLCAiRWdnIG9yIGVtYnJ5byIpDQoNCiMgRGVmaW5lIHRoZSBibGFjayBhbmQgZ3JleSBjb2xvciB0aGVtZQ0KY29sb3JfdGhlbWUgPC0gYygiI0ExNDMyMyIsICIjRDg2QzJGIiwgIiNFRTlFNUEiLCAiI0YzRTlBNSIpDQoNCiMgTWFraW5nIHByb3BvcnRpb24gZm9yIHRob3NlIHRoYXQgZGlkIHJlcG9ydCANCnN0YWdlX3N1bW1hcnlfZGVzY3JpYmVkIDwtIHN0YWdlX3N1bW1hcnlfYWxsICU+JQ0KICBkcGx5cjo6ZmlsdGVyKHNwZWNpZXNfc3RhZ2UgJWluJSBzdGFnZV9vcmRlcikgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6bXV0YXRlKG5fbW90aXZhdGlvbiA9IHN1bShuX3RvdGFsKSkgJT4lDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHByb3AgPSBuX3RvdGFsL25fbW90aXZhdGlvbikNCiAgICANCg0KDQojIENhbGN1bGF0ZSBjdW11bGF0aXZlIHBvc2l0aW9ucyBmb3IgdGV4dCBsYWJlbHMNCnN0YWdlX3N1bW1hcnlfZGVzY3JpYmVkIDwtIHN0YWdlX3N1bW1hcnlfZGVzY3JpYmVkICU+JQ0KICBkcGx5cjo6bXV0YXRlKHNwZWNpZXNfc3RhZ2UgPSBmYWN0b3Ioc3BlY2llc19zdGFnZSwgbGV2ZWxzID0gc3RhZ2Vfb3JkZXIpKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uKSAlPiUNCiAgZHBseXI6OmFycmFuZ2UoZGVzYyhzcGVjaWVzX3N0YWdlKSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKGN1bXVsYXRpdmVfcHJvcCA9IGN1bXN1bShwcm9wKSAtIHByb3AgLyA0KQ0KDQojIENyZWF0ZSB0aGUgcGxvdA0KbGlmZV9zdGFnZV9maWcgPC0gc3RhZ2Vfc3VtbWFyeV9kZXNjcmliZWQgJT4lDQogIG11dGF0ZShzdHVkeV9tb3RpdmF0aW9uID0gZmN0X3JlbGV2ZWwoc3R1ZHlfbW90aXZhdGlvbiwgIkJhc2ljIHJlc2VhcmNoIiwgIk1lZGljYWwiLCAiRW52aXJvbm1lbnRhbCIpKSAlPiUNCiAgZ2dwbG90KGFlcyh5ID0gcHJvcCwgeCA9IHN0dWR5X21vdGl2YXRpb24sIGZpbGwgPSBzcGVjaWVzX3N0YWdlLCBncm91cCA9IHNwZWNpZXNfc3RhZ2UpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCB3aWR0aCA9IDAuOSkgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcm91bmQocHJvcCwgMiksIHkgPSBjdW11bGF0aXZlX3Byb3ApLCBjb2xvciA9ICJ3aGl0ZSIsIHNpemUgPSAzKSArIA0KIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNvbG9yX3RoZW1lLCBuYW1lID0gIkxpZmUgc3RhZ2UiKSArIA0KICB0aGVtZV9jbGFzc2ljKCkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiKSArDQogIGxhYnMoDQogICAgeCA9ICJTdHVkeSBtb3RpdmF0aW9uIiwNCiAgICB5ID0gIlByb3BvcnRpb24gb2YgYWxsIHNwZWNpZXMgYXNzaWduZWQgdG8gYSBsaWZlIHN0YWdlIg0KICApICsNCiAgY29vcmRfZmxpcCgpDQoNCmxpZmVfc3RhZ2VfZmlnDQpgYGANCg0KDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCnNldHdkKGZpZ3VyZXNfcGF0aCkNCmdnc2F2ZSgic3BwX2xpZmVfc3RhZ2VfZmlnLnBkZiIsIHBsb3QgPSBsaWZlX3N0YWdlX2ZpZywgd2lkdGggPSAxMCwgaGVpZ2h0ID0gNSkNCmBgYA0KDQpMZXQncyBhbHNvIGxvb2sgYXQgaG93IG1hbnkgd2hlcmUgdW5rbm93biBvciBub3QgZGVzY3JpYmVkDQoNCmBgYHtyfQ0Kc3RhZ2Vfc3VtbWFyeV9pbmZvICA8LSBzdGFnZV9zdW1tYXJ5X2FsbCAlPiUgDQogIGRwbHlyOjptdXRhdGUoc3RhZ2VfcmVwb3J0ZWQgPSBpZl9lbHNlKHNwZWNpZXNfc3RhZ2UgPT0gIlVua25vd24gb3Igbm90IHNwZWNpZmllZCIsICJObyIsICJZZXMiKSkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3RhZ2VfcmVwb3J0ZWQpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IHN1bShuX3RvdGFsKSkNCg0Kbl90b3RhbCA8LSBzdGFnZV9zdW1tYXJ5X2luZm8gJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuX3RvdGFsID0gc3VtKG4pKSAlPiUgDQogIHB1bGwobl90b3RhbCkNCg0Kc3RhZ2Vfc3VtbWFyeV9pbmZvIDwtIHN0YWdlX3N1bW1hcnlfaW5mbyAlPiUgDQogIGRwbHlyOjptdXRhdGUocHJvcCA9IG4vbl90b3RhbCkNCmBgYA0KDQpIZXJlJ3MgdGhlIHBsb3QgDQoNCmBgYHtyLCBmaWcud2lkdGg9Mi41LCBmaWcuaGVpZ2h0PTV9DQojIERlZmluZSB0aGUgYmxhY2sgYW5kIGdyZXkgY29sb3IgdGhlbWUNCmJsYWNrX2FuZF9ncmV5IDwtIGMoIiNCQ0JFQzAiLCAiIzQxNDA0MiIpDQoNCnllc19vcmRlciA8LSBjKCJZZXMiLCAiTm8iKQ0KDQojIENhbGN1bGF0ZSBjdW11bGF0aXZlIHBvc2l0aW9ucyBmb3IgdGV4dCBsYWJlbHMNCnN0YWdlX3N1bW1hcnlfaW5mbyA8LSBzdGFnZV9zdW1tYXJ5X2luZm8gJT4lDQogIGRwbHlyOjptdXRhdGUoc3RhZ2VfcmVwb3J0ZWQgPSBmYWN0b3Ioc3RhZ2VfcmVwb3J0ZWQsIGxldmVscyA9IHllc19vcmRlcikpICU+JSANCiAgZHBseXI6OmFycmFuZ2UoZGVzYyhzdGFnZV9yZXBvcnRlZCkpICU+JSANCiAgZHBseXI6Om11dGF0ZShjdW11bGF0aXZlX3Byb3AgPSBjdW1zdW0ocHJvcCkgLSBwcm9wIC8gMikNCg0Kc3RhZ2VfaW5mb19maWcgPC0gc3RhZ2Vfc3VtbWFyeV9pbmZvICU+JQ0KICBkcGx5cjo6bXV0YXRlKHN0YWdlX3JlcG9ydGVkID0gZmFjdG9yKHN0YWdlX3JlcG9ydGVkLCBsZXZlbHMgPSB5ZXNfb3JkZXIpKSAlPiUgDQogIGdncGxvdChhZXMoeSA9IHByb3AsIHggPSAxLCBmaWxsID0gc3RhZ2VfcmVwb3J0ZWQpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCB3aWR0aCA9IDAuOSkgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcm91bmQocHJvcCwgMiksIHkgPSBjdW11bGF0aXZlX3Byb3ApLCBjb2xvciA9ICJ3aGl0ZSIpICsgDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGJsYWNrX2FuZF9ncmV5LCBuYW1lID0gIlN0YWdlIHJlcG9ydGVkIikgKyANCiAgdGhlbWVfY2xhc3NpYygpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IiwNCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksICAjIFJlbW92ZSB4LWF4aXMgdGV4dA0KICAgICAgICBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCkgICMgUmVtb3ZlIHgtYXhpcyB0aWNrcyANCiAgKSArDQogIGxhYnMoDQogICAgeCA9ICIiLA0KICAgIHkgPSAiUHJvcG9ydGlvbiBvZiBzcGVjaWVzIHRlc3RlZCBpbiB0aGUgZGF0YWJhc2UiDQogICkNCnN0YWdlX2luZm9fZmlnDQpgYGANCg0KYGBge3IsIHdhcm5pbmc9RkFMU0V9DQpzZXR3ZChmaWd1cmVzX3BhdGgpDQpnZ3NhdmUoInNwcF9zdGFnZV9pbmZvX2ZpZy5wZGYiLCBwbG90ID0gc3RhZ2VfaW5mb19maWcsIHdpZHRoID0gMi41LCBoZWlnaHQgPSA1KQ0KYGBgDQoNCiMjIDEyLjYgU3BlY2llcyBzZXggDQoNCkZpcnN0IG92ZXJhbGwgYnJlYWtkb3duIGJ5IGZlbWFsZSBhbmQgbWFsZSB3aXRob3V0IGluY2x1ZGluZyB1bnJlcG9ydGVkIG9yIGhlcm1hcGhyb2RpdGljIGFuaW1hbHMNCg0KYGBge3J9DQpFSVBBQUJfZGF0YWJhc2UgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkodW5pcXVlX3BvcHVsYXRpb25faWQpICU+JSANCiAgZHBseXI6OnNhbXBsZV9uKDEpICU+JSAjIHNhbXBsaW5nIG9uZSByb3cgcGVyIGFydGljbGUgcGVyIHNwZWNpZXMgKGkuZS4gaWdub3JpbmcgbXVsdGlwbGUgcm93cyBwZXIgYXJ0aWNsZSBmb3IgY29tcG91bmRzKQ0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHNwZWNpZXNfc2V4KSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBuKCkpICU+JQ0KICBkcGx5cjo6bXV0YXRlKHNwZWNpZXNfc2V4ID0gc3RyX3RyaW0oc3BlY2llc19zZXgpKSAlPiUNCiAgdGlkeXI6OnNlcGFyYXRlX3Jvd3Moc3BlY2llc19zZXgsIHNlcCA9ICI7IikgJT4lICMgZWFjaCBzcHAgaGFzIG11bHRpcGxlIGhhYml0YXRzIHRoZSBzdHJpbmcgbmVlZHMgc3BsaXR0aW5nDQogIGRwbHlyOjpncm91cF9ieShzcGVjaWVzX3NleCkgJT4lIA0KICBkcGx5cjo6c3VtbWFyaXNlKG5fYXJ0aWNsZXMgPSBzdW0obiksIC5ncm91cHMgPSAnZHJvcCcpICU+JSAgIyBub3cgYSBzdW0gZm9yIGVhY2ggaGFiaXRhdA0KICB0aWR5cjo6Y29tcGxldGUoc3BlY2llc19zZXgsIA0KICAgICAgICAgICAgICAgICAgZmlsbCA9IGxpc3Qobl9hcnRpY2xlcyA9IDApKSAlPiUgICMgbWFrZSBhIGZ1bGwgZGYgd2l0aCBlbXB0eSBjYXRlZ29yaWVzID0gMA0KICBkcGx5cjo6dW5ncm91cCgpICU+JQ0KICBkcGx5cjo6ZmlsdGVyKHNwZWNpZXNfc2V4ID09ICJGZW1hbGUiIHwgc3BlY2llc19zZXggPT0gIk1hbGUiKSAlPiUgDQogIGRwbHlyOjptdXRhdGUodG90YWxfc2V4ID0gc3VtKG5fYXJ0aWNsZXMpKSAlPiUgDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKG92ZXJhbGxfcGVyY2VudCA9IHJvdW5kKG5fYXJ0aWNsZXMvdG90YWxfc2V4KjEwMCwxKSkNCmBgYA0KDQoNCkxldCdzIHRha2UgYSBsb29rIGF0IHRoZSBzZXggb2Ygc3BwIHVzZWQgaW4gdGhlIEVJUEFBQiBkYXRhYmFzZQ0KDQpgYGB7cn0NCnNleF9zdW1tYXJ5X2FsbCA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkodW5pcXVlX3BvcHVsYXRpb25faWQpICU+JSANCiAgZHBseXI6OnNhbXBsZV9uKDEpICU+JSAjIHNhbXBsaW5nIG9uZSByb3cgcGVyIGFydGljbGUgcGVyIHNwZWNpZXMgKGkuZS4gaWdub3JpbmcgbXVsdGlwbGUgcm93cyBwZXIgYXJ0aWNsZSBmb3IgY29tcG91bmRzKQ0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHN0dWR5X21vdGl2YXRpb24sIHNwZWNpZXNfc2V4KSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBuKCkpICU+JQ0KICBkcGx5cjo6bXV0YXRlKHNwZWNpZXNfc2V4ID0gc3RyX3RyaW0oc3BlY2llc19zZXgpKSAlPiUNCiAgdGlkeXI6OnNlcGFyYXRlX3Jvd3Moc3BlY2llc19zZXgsIHNlcCA9ICI7IikgJT4lICMgZWFjaCBzcHAgaGFzIG11bHRpcGxlIGhhYml0YXRzIHRoZSBzdHJpbmcgbmVlZHMgc3BsaXR0aW5nDQogIGRwbHlyOjpncm91cF9ieShzcGVjaWVzX3NleCwgc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6c3VtbWFyaXNlKG5fYXJ0aWNsZXMgPSBzdW0obiksIC5ncm91cHMgPSAnZHJvcCcpICU+JSAgIyBub3cgYSBzdW0gZm9yIGVhY2ggaGFiaXRhdA0KICB0aWR5cjo6Y29tcGxldGUoc3BlY2llc19zZXgsIHN0dWR5X21vdGl2YXRpb24sIA0KICAgICAgICAgICAgICAgICAgZmlsbCA9IGxpc3Qobl9hcnRpY2xlcyA9IDApKSAlPiUgICMgbWFrZSBhIGZ1bGwgZGYgd2l0aCBlbXB0eSBjYXRlZ29yaWVzID0gMA0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHN0dWR5X21vdGl2YXRpb24pICU+JSANCiAgZHBseXI6Om11dGF0ZSh0b3RhbF9zZXggPSBzdW0obl9hcnRpY2xlcykpICU+JSANCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjptdXRhdGUob3ZlcmFsbF9wcm9wID0gbl9hcnRpY2xlcy90b3RhbF9zZXgpDQpzZXhfc3VtbWFyeV9hbGwNCmBgYA0KTGV0J3MgbG9vayBhdCBqdXN0IHRoZSBwcm9wb3J0aW9uIG9mIHRob3NlIGRlZmluZWQgYXMgbWFsZSBhbmQgZmVtYWxlDQoNCmBgYHtyfQ0Kc2V4X21hbGVfZmVtYWxlIDwtICBzZXhfc3VtbWFyeV9hbGwgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKHNwZWNpZXNfc2V4ID09ICJGZW1hbGUiIHwgc3BlY2llc19zZXggPT0gIk1hbGUiKSAlPiUgDQogIGRwbHlyOjpzZWxlY3QoLXRvdGFsX3NleCwgLW92ZXJhbGxfcHJvcCkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHRvdGFsX21hbGVfZmVtYWxlID0gc3VtKG5fYXJ0aWNsZXMpKSAlPiUgDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHByb3AgPSBuX2FydGljbGVzL3RvdGFsX21hbGVfZmVtYWxlKQ0KYGBgDQoNCk1ha2luZyB0aGUgcGxvdA0KDQpgYGB7ciwgZmlnLndpZHRoPTUsIGZpZy5oZWlnaHQ9Mi41fQ0Kc2V4X29yZGVyIDwtIGMoIkZlbWFsZSIsICJNYWxlIikNCg0KY29sb3JfdGhlbWUgPC0gYygiI2ViNDcyOSIsICIjMWI5MDlhIikNCg0KIyBDYWxjdWxhdGUgY3VtdWxhdGl2ZSBwb3NpdGlvbnMgZm9yIHRleHQgbGFiZWxzDQpzZXhfbWFsZV9mZW1hbGUgPC0gc2V4X21hbGVfZmVtYWxlICU+JQ0KICBkcGx5cjo6bXV0YXRlKHNwZWNpZXNfc2V4ID0gZmFjdG9yKHNwZWNpZXNfc2V4LCBsZXZlbHMgPSBzZXhfb3JkZXIpKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uKSAlPiUNCiAgZHBseXI6OmFycmFuZ2UoZGVzYyhzcGVjaWVzX3NleCkpICU+JSANCiAgZHBseXI6Om11dGF0ZShjdW11bGF0aXZlX3Byb3AgPSBjdW1zdW0ocHJvcCkgLSBwcm9wIC8gMikNCg0KIyBDcmVhdGUgdGhlIHBsb3QNCnNleF9maWcgPC0gc2V4X21hbGVfZmVtYWxlICU+JQ0KICBtdXRhdGUoc3R1ZHlfbW90aXZhdGlvbiA9IGZjdF9yZWxldmVsKHN0dWR5X21vdGl2YXRpb24sICJCYXNpYyByZXNlYXJjaCIsICJNZWRpY2FsIiwgIkVudmlyb25tZW50YWwiKSkgJT4lIA0KICBnZ3Bsb3QoYWVzKHkgPSBwcm9wLCB4ID0gc3R1ZHlfbW90aXZhdGlvbiwgZmlsbCA9IHNwZWNpZXNfc2V4LCBncm91cCA9IHNwZWNpZXNfc2V4KSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5Iiwgd2lkdGggPSAwLjkpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHJvdW5kKHByb3AsIDIpLCB5ID0gY3VtdWxhdGl2ZV9wcm9wKSwgY29sb3IgPSAid2hpdGUiLCBzaXplID0gMykgKyANCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sb3JfdGhlbWUsIG5hbWUgPSAiU2V4IikgKyANCiAgdGhlbWVfY2xhc3NpYygpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IikgKw0KICBsYWJzKA0KICAgIHggPSAiU3R1ZHkgbW90aXZhdGlvbiIsDQogICAgeSA9ICJQcm9wb3J0aW9uIG9mIGFsbCBzcGVjaWVzIGFzc2lnbmVkIHRvIGZlbWFsZSBvciBtYWxlIg0KICApICsNCiAgY29vcmRfZmxpcCgpDQoNCnNleF9maWcNCmBgYA0KDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQ0Kc2V0d2QoZmlndXJlc19wYXRoKQ0KZ2dzYXZlKCJzcHBfc2V4X2ZpZy5wZGYiLCBwbG90ID0gc2V4X2ZpZywgd2lkdGggPSAxMCwgaGVpZ2h0ID0gNSkNCmBgYA0KDQpOb3cgbGV0J3MgbG9vayBhdCB0aG9zZSBub3QgYXNzZ2luZWQgdG8gYSBzZXgNCg0KYGBge3J9DQpzZXhfc3VtbWFyeV9pbmZvIDwtIHNleF9zdW1tYXJ5X2FsbCAlPiUgDQogIGRwbHlyOjptdXRhdGUoc2V4X3JlcG9ydGVkID0gaWZfZWxzZShzcGVjaWVzX3NleCA9PSAiVW5rbm93biBvciBub3Qgc3BlY2lmaWVkIiwgIk5vIiwgIlllcyIpKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzZXhfcmVwb3J0ZWQpICU+JQ0KICBkcGx5cjo6cmVmcmFtZShuID0gc3VtKG5fYXJ0aWNsZXMpKQ0KDQpuX3RvdGFsIDwtIHNleF9zdW1tYXJ5X2luZm8gJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuX3RvdGFsID0gc3VtKG4pKSAlPiUgDQogIGRwbHlyOjpwdWxsKG5fdG90YWwpDQoNCnNleF9zdW1tYXJ5X2luZm8gPC0gc2V4X3N1bW1hcnlfaW5mbyAlPiUNCiAgZHBseXI6Om11dGF0ZShwcm9wID0gbi9uX3RvdGFsKQ0KYGBgDQoNCg0KSGVyZSdzIHRoZSBwbG90IA0KDQpgYGB7ciwgZmlnLndpZHRoPTIuNSwgZmlnLmhlaWdodD01fQ0KIyBEZWZpbmUgdGhlIGJsYWNrIGFuZCBncmV5IGNvbG9yIHRoZW1lDQpibGFja19hbmRfZ3JleSA8LSBjKCIjQkNCRUMwIiwgIiM0MTQwNDIiKQ0KDQp5ZXNfb3JkZXIgPC0gYygiWWVzIiwgIk5vIikNCg0KIyBDYWxjdWxhdGUgY3VtdWxhdGl2ZSBwb3NpdGlvbnMgZm9yIHRleHQgbGFiZWxzDQpzZXhfc3VtbWFyeV9pbmZvIDwtIHNleF9zdW1tYXJ5X2luZm8gJT4lDQogIGRwbHlyOjptdXRhdGUoc2V4X3JlcG9ydGVkID0gZmFjdG9yKHNleF9yZXBvcnRlZCwgbGV2ZWxzID0geWVzX29yZGVyKSkgJT4lIA0KICBkcGx5cjo6YXJyYW5nZShkZXNjKHNleF9yZXBvcnRlZCkpICU+JSANCiAgZHBseXI6Om11dGF0ZShjdW11bGF0aXZlX3Byb3AgPSBjdW1zdW0ocHJvcCkgLSBwcm9wIC8gMikNCg0Kc2V4X2luZm9fZmlnIDwtIHNleF9zdW1tYXJ5X2luZm8gJT4lDQogIGRwbHlyOjptdXRhdGUoc2V4X3JlcG9ydGVkID0gZmFjdG9yKHNleF9yZXBvcnRlZCwgbGV2ZWxzID0geWVzX29yZGVyKSkgJT4lIA0KICBnZ3Bsb3QoYWVzKHkgPSBwcm9wLCB4ID0gMSwgZmlsbCA9IHNleF9yZXBvcnRlZCkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHdpZHRoID0gMC45KSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSByb3VuZChwcm9wLCAyKSwgeSA9IGN1bXVsYXRpdmVfcHJvcCksIGNvbG9yID0gIndoaXRlIikgKyANCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYmxhY2tfYW5kX2dyZXksIG5hbWUgPSAiU2V4IHJlcG9ydGVkIikgKyANCiAgdGhlbWVfY2xhc3NpYygpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IiwNCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksICAjIFJlbW92ZSB4LWF4aXMgdGV4dA0KICAgICAgICBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCkgICMgUmVtb3ZlIHgtYXhpcyB0aWNrcyANCiAgICAgICAgKSArDQogIGxhYnMoDQogICAgeCA9ICIiLA0KICAgIHkgPSAiUHJvcG9ydGlvbiBvZiBhbGwgc3BlY2llcyINCiAgKQ0Kc2V4X2luZm9fZmlnDQpgYGANCg0KYGBge3IsIHdhcm5pbmc9RkFMU0V9DQpzZXR3ZChmaWd1cmVzX3BhdGgpDQpnZ3NhdmUoInNwcF9zZXhfaW5mb19maWcucGRmIiwgcGxvdCA9IHNleF9pbmZvX2ZpZywgd2lkdGggPSAyLjUsIGhlaWdodCA9IDUpDQpgYGANCg0KIyMgMTIuNyBTcGVjaWVzIHNvdXJjZQ0KDQpCcmVha2Rvd24gd2l0aG91dCB1bnJlcG9ydGVkIA0KDQpgYGB7cn0NCkVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIGRwbHlyOjpncm91cF9ieSh1bmlxdWVfcG9wdWxhdGlvbl9pZCkgJT4lIA0KICBkcGx5cjo6c2FtcGxlX24oMSkgJT4lICMgc2FtcGxpbmcgb25lIHJvdyBwZXIgYXJ0aWNsZSBwZXIgc3BlY2llcyAoaS5lLiBpZ25vcmluZyBtdWx0aXBsZSByb3dzIHBlciBhcnRpY2xlIGZvciBjb21wb3VuZHMpDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3BlY2llc19zb3VyY2UpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IG4oKSkgJT4lDQogIGRwbHlyOjptdXRhdGUoc3BlY2llc19zb3VyY2UgPSBzdHJfdHJpbShzcGVjaWVzX3NvdXJjZSkpICU+JQ0KICB0aWR5cjo6c2VwYXJhdGVfcm93cyhzcGVjaWVzX3NvdXJjZSwgc2VwID0gIjsiKSAlPiUgIyBlYWNoIHNwcCBoYXMgbXVsdGlwbGUgaGFiaXRhdHMgdGhlIHN0cmluZyBuZWVkcyBzcGxpdHRpbmcNCiAgZHBseXI6Omdyb3VwX2J5KHNwZWNpZXNfc291cmNlKSAlPiUgDQogIGRwbHlyOjpzdW1tYXJpc2Uobl9hcnRpY2xlcyA9IHN1bShuKSwgLmdyb3VwcyA9ICdkcm9wJykgJT4lICAjIG5vdyBhIHN1bSBmb3IgZWFjaCBoYWJpdGF0DQogIHRpZHlyOjpjb21wbGV0ZShzcGVjaWVzX3NvdXJjZSwgDQogICAgICAgICAgICAgICAgICBmaWxsID0gbGlzdChuX2FydGljbGVzID0gMCkpICU+JSAgIyBtYWtlIGEgZnVsbCBkZiB3aXRoIGVtcHR5IGNhdGVnb3JpZXMgPSAwDQogIGRwbHlyOjpmaWx0ZXIoc3BlY2llc19zb3VyY2UgIT0gIk5vdCByZXBvcnRlZCIpICU+JSANCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjptdXRhdGUodG90YWxfc291cmNlID0gc3VtKG5fYXJ0aWNsZXMpKSAlPiUgDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKG92ZXJhbGxfcGVyY2VudCA9IHJvdW5kKG5fYXJ0aWNsZXMvdG90YWxfc291cmNlKjEwMCwgMSkpICU+JSANCiAgZHBseXI6OmFycmFuZ2UoZGVzYyhvdmVyYWxsX3BlcmNlbnQpKQ0KYGBgDQoNCkxldCdzIGxvb2sgYXQgd2hlcmUgdGhlIGFuaW1hbHMgd2VyZSBzb3VyY2VkIGZvciBhcnRpY2xlcyBpbiB0aGUgRUlQQUFCIGRhdGFiYXNlDQoNCmBgYHtyfQ0Kc291cmNlX3N1bW1hcnlfYWxsIDwtIEVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIGRwbHlyOjpncm91cF9ieSh1bmlxdWVfcG9wdWxhdGlvbl9pZCkgJT4lIA0KICBkcGx5cjo6c2FtcGxlX24oMSkgJT4lICMgc2FtcGxpbmcgb25lIHJvdyBwZXIgYXJ0aWNsZSBwZXIgc3BlY2llcyAoaS5lLiBpZ25vcmluZyBtdWx0aXBsZSByb3dzIHBlciBhcnRpY2xlIGZvciBjb21wb3VuZHMpDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3R1ZHlfbW90aXZhdGlvbiwgc3BlY2llc19zb3VyY2UpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IG4oKSkgJT4lDQogIGRwbHlyOjptdXRhdGUoc3BlY2llc19zb3VyY2UgPSBzdHJfdHJpbShzcGVjaWVzX3NvdXJjZSkpICU+JQ0KICB0aWR5cjo6c2VwYXJhdGVfcm93cyhzcGVjaWVzX3NvdXJjZSwgc2VwID0gIjsiKSAlPiUgIyBlYWNoIHNwcCBoYXMgbXVsdGlwbGUgaGFiaXRhdHMgdGhlIHN0cmluZyBuZWVkcyBzcGxpdHRpbmcNCiAgZHBseXI6Omdyb3VwX2J5KHNwZWNpZXNfc291cmNlLCBzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIGRwbHlyOjpzdW1tYXJpc2Uobl9hcnRpY2xlcyA9IHN1bShuKSwgLmdyb3VwcyA9ICdkcm9wJykgJT4lICAjIG5vdyBhIHN1bSBmb3IgZWFjaCBoYWJpdGF0DQogIHRpZHlyOjpjb21wbGV0ZShzcGVjaWVzX3NvdXJjZSwgc3R1ZHlfbW90aXZhdGlvbiwgDQogICAgICAgICAgICAgICAgICBmaWxsID0gbGlzdChuX2FydGljbGVzID0gMCkpICU+JSAgIyBtYWtlIGEgZnVsbCBkZiB3aXRoIGVtcHR5IGNhdGVnb3JpZXMgPSAwDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHRvdGFsX3NvdXJjZSA9IHN1bShuX2FydGljbGVzKSkgJT4lIA0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6Om11dGF0ZShvdmVyYWxsX3Byb3AgPSBuX2FydGljbGVzL3RvdGFsX3NvdXJjZSkNCnNvdXJjZV9zdW1tYXJ5X2FsbA0KYGBgDQoNCmBgYHtyfQ0Kc291cmNlX3N1bW1hcnkgPC0gc291cmNlX3N1bW1hcnlfYWxsICU+JSANCiAgZHBseXI6OmZpbHRlcihzcGVjaWVzX3NvdXJjZSAhPSAiTm90IHJlcG9ydGVkIikgJT4lIA0KICBkcGx5cjo6c2VsZWN0KHNwZWNpZXNfc291cmNlLCBzdHVkeV9tb3RpdmF0aW9uLCBuX2FydGljbGVzKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIGRwbHlyOjptdXRhdGUodG90YWxfcmVwb3J0ZWQgPSBzdW0obl9hcnRpY2xlcykpICU+JSANCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjptdXRhdGUocHJvcCA9IG5fYXJ0aWNsZXMvdG90YWxfcmVwb3J0ZWQpDQpzb3VyY2Vfc3VtbWFyeQ0KYGBgDQoNCmBgYHtyLCBmaWcud2lkdGg9NywgZmlnLmhlaWdodD0yLjV9DQpzb3VyY2Vfb3JkZXIgPC0gYygiV2lsZCBjb2xsZWN0ZWQiLCAiTGFiIHN0b2NrIGZyb20gd2lsZCBwb3B1bGF0aW9uIiwgIkxhYiBzdG9jayBvZiB1bmRpc2Nsb3NlZCBvcmlnaW4iLCANCiAgICAgICAgICAgICAgICAgICJMYWIgc3RvY2sgZnJvbSBjb21tZXJjaWFsIHN1cHBsaWVyIiwgIkNvbW1lcmNpYWwgc3VwcGxpZXIgb3IgZmlzaCBmYXJtIikNCg0KIyBEZWZpbmUgdGhlIGJsYWNrIGFuZCBncmV5IGNvbG9yIHRoZW1lDQpjb2xvcl90aGVtZSA8LSBjKCIjNjA3QzNCIiwgIiNBN0QyNzEiLCAiIzZCNkU3MCIsICIjQTY2RUFGIiwgIiM2MTM0NkIiKQ0KDQojIENhbGN1bGF0ZSBjdW11bGF0aXZlIHBvc2l0aW9ucyBmb3IgdGV4dCBsYWJlbHMNCnNvdXJjZV9zdW1tYXJ5IDwtIHNvdXJjZV9zdW1tYXJ5ICU+JQ0KICBkcGx5cjo6bXV0YXRlKHNwZWNpZXNfc291cmNlID0gZmFjdG9yKHNwZWNpZXNfc291cmNlLCBsZXZlbHMgPSBzb3VyY2Vfb3JkZXIpKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uKSAlPiUNCiAgZHBseXI6OmFycmFuZ2UoZGVzYyhzcGVjaWVzX3NvdXJjZSkpICU+JSANCiAgZHBseXI6Om11dGF0ZShjdW11bGF0aXZlX3Byb3AgPSBjdW1zdW0ocHJvcCkgLSBwcm9wIC8gNSkNCg0KIyBDcmVhdGUgdGhlIHBsb3QNCnNvdXJjZV9maWcgPC0gc291cmNlX3N1bW1hcnkgJT4lDQogIG11dGF0ZShzdHVkeV9tb3RpdmF0aW9uID0gZmN0X3JlbGV2ZWwoc3R1ZHlfbW90aXZhdGlvbiwgIkJhc2ljIHJlc2VhcmNoIiwgIk1lZGljYWwiLCAiRW52aXJvbm1lbnRhbCIpKSAlPiUgDQogIGdncGxvdChhZXMoeSA9IHByb3AsIHggPSBzdHVkeV9tb3RpdmF0aW9uLCBmaWxsID0gc3BlY2llc19zb3VyY2UsIGdyb3VwID0gc3BlY2llc19zb3VyY2UpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCB3aWR0aCA9IDAuOSkgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcm91bmQocHJvcCwgMiksIHkgPSBjdW11bGF0aXZlX3Byb3ApLCBjb2xvciA9ICJ3aGl0ZSIsIHNpemUgPSAzKSArIA0KIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNvbG9yX3RoZW1lLCBuYW1lID0gIkxpZmUgc3RhZ2UiKSArIA0KICB0aGVtZV9jbGFzc2ljKCkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiKSArDQogIGxhYnMoDQogICAgeCA9ICJTdHVkeSBtb3RpdmF0aW9uIiwNCiAgICB5ID0gIlByb3BvcnRpb24gb2YgYWxsIHNwZWNpZXMgd2l0aCBhIGRlc2NyaWJlZCBzb3VyY2UiDQogICkgKw0KICBjb29yZF9mbGlwKCkNCg0Kc291cmNlX2ZpZw0KYGBgDQoNCg0KYGBge3IsIHdhcm5pbmc9RkFMU0V9DQpzZXR3ZChmaWd1cmVzX3BhdGgpDQpnZ3NhdmUoInNwcF9zb3VyY2VfZmlnLnBkZiIsIHBsb3QgPSBzb3VyY2VfZmlnLCB3aWR0aCA9IDEwLCBoZWlnaHQgPSA1KQ0KYGBgDQoNCk5vdyBsZXQncyBsb29rIGF0IHRob3NlIG5vdCBhc3NpZ25lZCBhIHNvdXJjZQ0KDQpgYGB7cn0NCnNvdXJjZV9zdW1tYXJ5X2luZm8gPC0gc291cmNlX3N1bW1hcnlfYWxsICU+JSANCiAgZHBseXI6Om11dGF0ZShzb3VyY2VfcmVwb3J0ZWQgPSBpZl9lbHNlKHNwZWNpZXNfc291cmNlID09ICJOb3QgcmVwb3J0ZWQiLCAiTm8iLCAiWWVzIikpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHNvdXJjZV9yZXBvcnRlZCkgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gc3VtKG5fYXJ0aWNsZXMpKQ0KDQpuX3RvdGFsIDwtIHNvdXJjZV9zdW1tYXJ5X2luZm8gJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuX3RvdGFsID0gc3VtKG4pKSAlPiUgDQogIGRwbHlyOjpwdWxsKG5fdG90YWwpDQogIA0Kc291cmNlX3N1bW1hcnlfaW5mbyA8LSBzb3VyY2Vfc3VtbWFyeV9pbmZvICU+JSANCiAgZHBseXI6Om11dGF0ZShwcm9wID0gbi9uX3RvdGFsKQ0KYGBgDQoNCkhlcmUncyB0aGUgcGxvdCANCg0KYGBge3IsIGZpZy53aWR0aD0yLjUsIGZpZy5oZWlnaHQ9NX0NCiMgRGVmaW5lIHRoZSBibGFjayBhbmQgZ3JleSBjb2xvciB0aGVtZQ0KYmxhY2tfYW5kX2dyZXkgPC0gYygiI0JDQkVDMCIsICIjNDE0MDQyIikNCg0KeWVzX29yZGVyIDwtIGMoIlllcyIsICJObyIpDQoNCiMgQ2FsY3VsYXRlIGN1bXVsYXRpdmUgcG9zaXRpb25zIGZvciB0ZXh0IGxhYmVscw0Kc291cmNlX3N1bW1hcnlfaW5mbyA8LSBzb3VyY2Vfc3VtbWFyeV9pbmZvICU+JQ0KICBkcGx5cjo6bXV0YXRlKHNvdXJjZV9yZXBvcnRlZCA9IGZhY3Rvcihzb3VyY2VfcmVwb3J0ZWQsIGxldmVscyA9IHllc19vcmRlcikpICU+JSANCiAgZHBseXI6OmFycmFuZ2UoZGVzYyhzb3VyY2VfcmVwb3J0ZWQpKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoY3VtdWxhdGl2ZV9wcm9wID0gY3Vtc3VtKHByb3ApIC0gcHJvcCAvIDIpDQoNCnNvdXJjZV9pbmZvX2ZpZyA8LSBzb3VyY2Vfc3VtbWFyeV9pbmZvICU+JQ0KICBkcGx5cjo6bXV0YXRlKHNvdXJjZV9yZXBvcnRlZCA9IGZhY3Rvcihzb3VyY2VfcmVwb3J0ZWQsIGxldmVscyA9IHllc19vcmRlcikpICU+JSANCiAgZ2dwbG90KGFlcyh5ID0gcHJvcCwgeCA9IDEsIGZpbGwgPSBzb3VyY2VfcmVwb3J0ZWQpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCB3aWR0aCA9IDAuOSkgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcm91bmQocHJvcCwgMiksIHkgPSBjdW11bGF0aXZlX3Byb3ApLCBjb2xvciA9ICJ3aGl0ZSIpICsgDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGJsYWNrX2FuZF9ncmV5LCBuYW1lID0gIlNvdXJjZSByZXBvcnRlZCIpICsgDQogIHRoZW1lX2NsYXNzaWMoKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsDQogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLCAgIyBSZW1vdmUgeC1heGlzIHRleHQNCiAgICAgICAgYXhpcy50aWNrcy54ID0gZWxlbWVudF9ibGFuaygpICAjIFJlbW92ZSB4LWF4aXMgdGlja3MgDQogICAgICAgICkgKw0KICBsYWJzKA0KICAgIHggPSAiIiwNCiAgICB5ID0gIlByb3BvcnRpb24gb2YgYWxsIHNwZWNpZXMiDQogICkNCnNvdXJjZV9pbmZvX2ZpZw0KYGBgDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQ0Kc2V0d2QoZmlndXJlc19wYXRoKQ0KZ2dzYXZlKCJzcHBfc291cmNlX2luZm9fZmlnLnBkZiIsIHBsb3QgPSBzb3VyY2VfaW5mb19maWcsIHdpZHRoID0gNSwgaGVpZ2h0ID0gMTApDQpgYGANCg0KDQojIDEzIENvbXBvdW5kcyANCg0KIyMgMTMuMSBOdW1iZXIgb2YgY29tcG91bmRzIGluIGRhdGFiYXNlDQoNClRoZXJlIGFyZSA0MjYgZGlzdGluY3QgY29tcG91bmRzIGluIHRoZSBkYXRhYmFzZQ0KDQpgYGB7cn0NCkVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIGRwbHlyOjpkaXN0aW5jdChjb21wb3VuZF9uYW1lKSAlPiUgDQogIG5yb3coKQ0KYGBgDQoNCg0KIyMjIDEzLjEuMSBOdW1iZXIgb2YgY29tcG91bmRzIHBlciBzdHVkeQ0KDQpgYGB7cn0NCmFydGljbGVfbiA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lIA0KICBkcGx5cjo6ZGlzdGluY3QoYXJ0aWNsZV9pZCkgJT4lIA0KICBucm93KC4pDQoNCmNvbXBvdW5kX25fc3VtbWFyeSA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoYXJ0aWNsZV9pZCkgJT4lIA0KICBkcGx5cjo6c2FtcGxlX24oMSkgJT4lIA0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KGNvbXBvdW5kX24pICU+JQ0KICBkcGx5cjo6cmVmcmFtZShuID0gbigpLA0KICAgICAgICAgICAgICAgICAgIHBlcmNlbnQgPSByb3VuZCgobi9hcnRpY2xlX24pKjEwMCwxKSkNCg0KY29tcG91bmRfbl9zdW1tYXJ5DQpgYGANCg0KSG93IG1uYXkgdXNlZCBtb3JlIHRoZW4gNQ0KDQpgYGB7cn0NCmNvbXBvdW5kX25fc3VtbWFyeSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIoY29tcG91bmRfbiA+IDUpICU+JSANCiAgcmVmcmFtZShuID0gc3VtKG4pLA0KICAgICAgICAgIHBlcmNlbnQgPSByb3VuZCgobi9hcnRpY2xlX24pKjEwMCwxKSkNCmBgYA0KDQoNCmBgYHtyfQ0KY29tcG91bmRfbl9zdW1tYXJ5IDwtIEVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShhcnRpY2xlX2lkKSAlPiUgDQogIGRwbHlyOjpzYW1wbGVfbigxKSAlPiUgDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoY29tcG91bmRfbiwgc3R1ZHlfbW90aXZhdGlvbikgJT4lDQogIGRwbHlyOjpzdW1tYXJpc2UobiA9IG4oKSwgLmdyb3VwcyA9ICdkcm9wJykgJT4lIA0KICB0aWR5cjo6Y29tcGxldGUoY29tcG91bmRfbiwgc3R1ZHlfbW90aXZhdGlvbiwgZmlsbCA9IGxpc3QobiA9IDApKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIGRwbHlyOjptdXRhdGUodG90YWxfbW90aXZhdGlvbiA9IHN1bShuKSkgJT4lIA0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6Om11dGF0ZShwcm9wX21vdGl2YXRpb24gPSBuL3RvdGFsX21vdGl2YXRpb24pDQoNCmNvbXBvdW5kX25fc3VtbWFyeQ0KYGBgDQoNCg0KYGBge3J9DQojIERlZmluZSB0aGUgY29sb3VyIHBhbGV0dGUNCm1vdGl2YXRpb25fY29sb3VyX3RoZW1lIDwtIGMoIiM2MEJENkMiLCAiI0QzNTlBMSIsICIjM0M4MkM0IikgIyBNYWtpbmcgY29sb3VyIHRoZW1lIHRvIGFwcGx5IHRvIHBsb3QNCg0KY29tcG91bmRfbl9vZGVyIDwtIGMoMTo5LCAiPjEwIikNCg0KY29tcG91bmRfbl9maWcgPC0gY29tcG91bmRfbl9zdW1tYXJ5ICU+JSANCiAgZHBseXI6Om11dGF0ZSgNCiAgICBjb21wb3VuZF9uID0gYXMuY2hhcmFjdGVyKGlmX2Vsc2UoY29tcG91bmRfbiA+IDEwLCAxMCwgY29tcG91bmRfbikpLCAjIEdyb3VwaW5nIGNhc2VzIGFib3ZlIDEwDQogICAgY29tcG91bmRfbiA9IGlmX2Vsc2UoY29tcG91bmRfbiA9PSAiMTAiLCAiPjEwIiwgY29tcG91bmRfbikNCiAgICApICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KGNvbXBvdW5kX24sIHN0dWR5X21vdGl2YXRpb24pICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IHN1bShuKSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKGNvbXBvdW5kX24gPSBmYWN0b3IoY29tcG91bmRfbiwgbGV2ZWxzID0gY29tcG91bmRfbl9vZGVyKSkgJT4lDQogIGdncGxvdChhZXMoeD1jb21wb3VuZF9uLCB5PW4sIGNvbG91ciA9IHN0dWR5X21vdGl2YXRpb24sIGZpbGwgPSBzdHVkeV9tb3RpdmF0aW9uLCBncm91cCA9IHN0dWR5X21vdGl2YXRpb24pKSArDQogIGdlb21fY29sKHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjgpLCB3aWR0aCA9IDAuMSkgKw0KICBnZW9tX3BvaW50KHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjgpLCBzaXplID0gMykgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gbiksIHZqdXN0PS0wLjYsIHNpemU9My41LCBjb2xvcj0iYmxhY2siLCBwb3NpdGlvbiA9ICBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOCkpICsNCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBtb3RpdmF0aW9uX2NvbG91cl90aGVtZSwgbmFtZSA9ICJTdHVkeSBtb3RpdmF0aW9uIikgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBtb3RpdmF0aW9uX2NvbG91cl90aGVtZSwgbmFtZSA9ICJTdHVkeSBtb3RpdmF0aW9uIikgKw0KICB0aGVtZV9jbGFzc2ljKCkgKw0KICAgbGFicygNCiAgICB4ID0gIiIsDQogICAgeSA9ICJOdW1iZXIgb2Ygc3R1ZGllcyINCiAgKSArDQogICB0aGVtZSgpDQoNCmNvbXBvdW5kX25fZmlnDQpgYGANCg0KDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCnNldHdkKGZpZ3VyZXNfcGF0aCkNCmdnc2F2ZSgiY29tcF9jb21wb3VuZF9uX2ZpZy5wZGYiLCBwbG90ID0gY29tcG91bmRfbl9maWcsIHdpZHRoID0gMTAsIGhlaWdodCA9IDUpDQpgYGANCg0KIyMgMTMuMiBUaGVycHV0aWMgZGl2ZXJzaXR5IGluIHRoZSBkYXRhYmFzZQ0KDQpGaXJzdCBsZXRzIHNlZSBob3cgbWFueSBjb21wb3VuZHMgaGF2ZSBhbiBBVEMgY2xhc3NpZmljYXRpb24uIA0KDQozMDUgb3V0IG9mIDQyNiAoNzEuNiUpDQoNCg0KYGBge3J9DQpFSVBBQUJfZGF0YWJhc2UgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoY29tcG91bmRfbmFtZSkgJT4lIA0KICBkcGx5cjo6c2FtcGxlX24oMSkgJT4lICMgc2FtcGxpbmcgb25lIHJvdyBwZXIgYXJ0aWNsZSBwZXIgc3BlY2llcyAoaS5lLiBpZ25vcmluZyBtdWx0aXBsZSByb3dzIHBlciBhcnRpY2xlIGZvciBjb21wb3VuZHMpDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoY29tcG91bmRfYXRjX2Jvb2xlYW4pICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IGxlbmd0aChjb21wb3VuZF9hdGNfYm9vbGVhbikpDQpgYGANCg0KDQojIyMgMTMuMi4xIEFUQyBsZXZlbCAxDQoNCkxldCdzIHNlZW0gaG93IG1hbnkgY2xhc3NlcyB0aGVyZSBhcmUgYXQgdGhlIEFuYXRvbWljYWwgVGhlcmFwZXV0aWMgQ2hlbWljYWwgKEFUQykgbGV2ZWwgMSANCg0KVGhlcmUgYXJlIDE0IGNsYXNzZXMgYXQgdGhlIDFzdCBBVEMgbGV2ZWwgKHRoZSBoaWdoZXN0IGNsYXNzIG9mIHRoZSBBVEMpLiBUaGlzIGlzIGV2ZXIgY2xhc3MgYXQgdGhlIGZpcnN0IGxldmVsDQoNCmBgYHtyfQ0Kbl9jb21wb3VuZF9hdGMgPC0gRUlQQUFCX2RhdGFiYXNlICU+JSANCiAgZHBseXI6OmZpbHRlcihjb21wb3VuZF9hdGNfYm9vbGVhbiA9PSAiWWVzIikgJT4lIA0KICBkcGx5cjo6ZGlzdGluY3QoY29tcG91bmRfbmFtZSkgJT4lIA0KICBucm93KC4pDQoNCmNvbXBvdW5kX0FUQ19MMV9zdW1tYXJ5IDwtIEVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShjb21wb3VuZF9uYW1lKSAlPiUgDQogIGRwbHlyOjpzYW1wbGVfbigxKSAlPiUgIyBzYW1wbGluZyBvbmUgcm93IHBlciBhcnRpY2xlIHBlciBzcGVjaWVzIChpLmUuIGlnbm9yaW5nIG11bHRpcGxlIHJvd3MgcGVyIGFydGljbGUgZm9yIGNvbXBvdW5kcykNCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIoY29tcG91bmRfYXRjX2Jvb2xlYW4gPT0gIlllcyIpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KGNvbXBvdW5kX2F0Y19sZXZlbF8xKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBuKCkpICU+JQ0KICBkcGx5cjo6bXV0YXRlKGNvbXBvdW5kX2F0Y19sZXZlbF8xID0gc3RyX3RyaW0oY29tcG91bmRfYXRjX2xldmVsXzEpKSAlPiUNCiAgdGlkeXI6OnNlcGFyYXRlX3Jvd3MoY29tcG91bmRfYXRjX2xldmVsXzEsIHNlcCA9ICI7IikgJT4lICMgZWFjaCBzcHAgaGFzIG11bHRpcGxlIGhhYml0YXRzIHRoZSBzdHJpbmcgbmVlZHMgc3BsaXR0aW5nDQogIGRwbHlyOjpncm91cF9ieShjb21wb3VuZF9hdGNfbGV2ZWxfMSkgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gc3VtKG4pLA0KICAgICAgICAgICAgICAgICBwZXJjZW50ID0gcm91bmQobi9uX2NvbXBvdW5kX2F0YyoxMDAsMSksDQogICAgICAgICAgICAgICAgIG1lYXN1cmUgPSAiY29tcG91bmRzIikgJT4lICMgbm93IGEgc3VtIGZvciBlYWNoIGhhYml0YXQNCiAgYXJyYW5nZShkZXNjKG4pKQ0KDQpjb21wb3VuZF9BVENfTDFfc3VtbWFyeQ0KYGBgDQpOb3cgd2Ugd2lsbCBtYWtlIGEgc2ltaWxhciBkYXRhIGZpbGUgdG8gbG9vayBhdCB0aGUgb3ZlcmFsbCB1c2UgaW4gdGhlIGRhdGFiYXNlIGF0IGVhY2ggQVRDIGxldmVsIDENCg0KYGBge3J9DQpuX2RhdGFfYXRjIDwtIEVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIoY29tcG91bmRfYXRjX2Jvb2xlYW4gPT0gIlllcyIpICU+JSANCiAgbnJvdyguKQ0KDQpjb21wb3VuZF9BVENfTDFfZGF0YV9zdW1tYXJ5IDwtIEVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIoY29tcG91bmRfYXRjX2Jvb2xlYW4gPT0gIlllcyIpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KGNvbXBvdW5kX2F0Y19sZXZlbF8xKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBuKCkpICU+JQ0KICBkcGx5cjo6bXV0YXRlKGNvbXBvdW5kX2F0Y19sZXZlbF8xID0gc3RyX3RyaW0oY29tcG91bmRfYXRjX2xldmVsXzEpKSAlPiUNCiAgdGlkeXI6OnNlcGFyYXRlX3Jvd3MoY29tcG91bmRfYXRjX2xldmVsXzEsIHNlcCA9ICI7IikgJT4lICMgZWFjaCBzcHAgaGFzIG11bHRpcGxlIGhhYml0YXRzIHRoZSBzdHJpbmcgbmVlZHMgc3BsaXR0aW5nDQogIGRwbHlyOjpncm91cF9ieShjb21wb3VuZF9hdGNfbGV2ZWxfMSkgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gc3VtKG4pLA0KICAgICAgICAgICAgICAgICBwZXJjZW50ID1yb3VuZChuL25fZGF0YV9hdGMqMTAwLDEpLA0KICAgICAgICAgICAgICAgICBtZWFzdXJlID0gImRhdGEiKSAlPiUgIyBub3cgYSBzdW0gZm9yIGVhY2ggaGFiaXRhdA0KICBhcnJhbmdlKGRlc2MocGVyY2VudCkpDQpjb21wb3VuZF9BVENfTDFfZGF0YV9zdW1tYXJ5DQpgYGANCg0KDQpgYGB7cn0NCkFUQ19MMV9zdW1tYXJ5IDwtIGNvbXBvdW5kX0FUQ19MMV9zdW1tYXJ5ICU+JSANCiAgcmJpbmQoLiwgY29tcG91bmRfQVRDX0wxX2RhdGFfc3VtbWFyeSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHZhbHVlID0gaWZfZWxzZShtZWFzdXJlID09ICJjb21wb3VuZHMiLCBuLCBwZXJjZW50KSkNCmBgYA0KDQoNClRoaXMgcGxvdCBzaG93cyB0aGUgbnVtYmVyIG9mIGRpZmZlcmVudCBjb21wb3VuZHMgaW4gZWFjaCBBVEMgY2xhc3NpZmljYXRpb24gYXMgd2VsbCBhcyB0aGUgdG90YWwgcHJvcG9ydGlvbiBvZiBkYXRhIGl0IG1ha2VzIHVwIA0KDQpgYGB7cn0NCm1lYXN1cmVfY29sb3VyX3RoZW1lIDwtIGMoImJsYWNrIiwgImdyZXkiKSAjIE1ha2luZyBjb2xvdXIgdGhlbWUgdG8gYXBwbHkgdG8gcGxvdA0KDQojIE1ha2luZyBhIGxpc3Qgb2YgYWN0IG5hbWVzIGluIHRoZSBvcmRlciB0aGF0IHdlIHdhbnQgdGhlbSBpbiB0aGUgcGxvdCANCmxldmVsXzFfb3JkZXIgPC0gQVRDX0wxX3N1bW1hcnkgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKG1lYXN1cmUgPT0gImRhdGEiKSAlPiUgDQogIGRwbHlyOjphcnJhbmdlKHZhbHVlKSAlPiUgDQogIGRwbHlyOjpwdWxsKGNvbXBvdW5kX2F0Y19sZXZlbF8xKQ0KDQojIE1ha2luZyB0aGUgcGxvdA0KYXRjX2xldmVsXzFfZmlnIDwtIEFUQ19MMV9zdW1tYXJ5ICU+JSANCiAgZHBseXI6Om11dGF0ZShjb21wb3VuZF9hdGNfbGV2ZWxfMSA9IGZhY3Rvcihjb21wb3VuZF9hdGNfbGV2ZWxfMSwgbGV2ZWxzID0gbGV2ZWxfMV9vcmRlcikpICU+JSANCiAgZ2dwbG90KGFlcyh4PWNvbXBvdW5kX2F0Y19sZXZlbF8xLCB5PXZhbHVlLCBjb2xvdXIgPSBtZWFzdXJlLCBmaWxsID0gbWVhc3VyZSwgZ3JvdXAgPSBtZWFzdXJlKSkgKw0KICBnZW9tX2NvbChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC44KSwgd2lkdGggPSAwLjIsIGNvbG91ciA9IE5BKSArDQogIGdlb21fcG9pbnQocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOCksIHNpemUgPSAzKSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSB2YWx1ZSksIGhqdXN0PS0wLjYsIHNpemU9My41LCBjb2xvcj0iYmxhY2siLCBwb3NpdGlvbiA9ICBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOCkpICsNCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBtZWFzdXJlX2NvbG91cl90aGVtZSwgbmFtZSA9ICJWYWx1ZSB0eXBlIikgKw0KICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gbWVhc3VyZV9jb2xvdXJfdGhlbWUsIG5hbWUgPSAiVmFsdWUgdHlwZSIpICsNCiAgY29vcmRfZmxpcCgpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKA0KICAgIG5hbWUgPSAiTnVtYmVyIG9mIGRpc3RpbmN0IGNvbXBvdW5kcyIsDQogICAgc2VjLmF4aXMgPSBzZWNfYXhpcyh+IC4gLCBuYW1lID0gIlRvdGFsIHByb3BvcnRpb24gb2YgdGhlIGRhdGFiYXNlIikgIyBBZGp1c3Qgc2NhbGluZyBpZiBuZWVkZWQNCiAgKSArDQogIHRoZW1lX2NsYXNzaWMoKSArDQogICBsYWJzKA0KICAgIHggPSAiIiwNCiAgICB5ID0gIk51bWJlciBvZiBkaXN0aWN0IHNwZWNpZXMgaW4gdGhlIGRhdGFiYXNlIg0KICApICsNCiAgIHRoZW1lKCkNCg0KYXRjX2xldmVsXzFfZmlnDQpgYGANCg0KDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCnNldHdkKGZpZ3VyZXNfcGF0aCkNCmdnc2F2ZSgiY29tcF9hdGNfbGV2ZWxfMV9maWcucGRmIiwgcGxvdCA9IGF0Y19sZXZlbF8xX2ZpZywgd2lkdGggPSAxMCwgaGVpZ2h0ID0gMTApDQpgYGANCg0KIyMjIDEzLjIuMiBBVEMgbGV2ZWwgMw0KDQoNCkxldCdzIHNlZW0gaG93IG1hbnkgY2xhc3NlcyB0aGVyZSBhcmUgYXQgdGhlIEFuYXRvbWljYWwgVGhlcmFwZXV0aWMgQ2hlbWljYWwgKEFUQykgbGV2ZWwgMw0KDQpUaGVyZSBhcmUgMTMxIGRpc3RpbmN0IGNsYXNzZXMNCg0KDQpgYGB7cn0NCm5fY29tcG91bmRfYXRjIDwtIEVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIoY29tcG91bmRfYXRjX2Jvb2xlYW4gPT0gIlllcyIpICU+JSANCiAgZHBseXI6OmRpc3RpbmN0KGNvbXBvdW5kX25hbWUpICU+JSANCiAgbnJvdyguKQ0KDQpjb21wb3VuZF9BVENfTDNfc3VtbWFyeSA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoY29tcG91bmRfbmFtZSkgJT4lIA0KICBkcGx5cjo6c2FtcGxlX24oMSkgJT4lICMgc2FtcGxpbmcgb25lIHJvdyBwZXIgYXJ0aWNsZSBwZXIgc3BlY2llcyAoaS5lLiBpZ25vcmluZyBtdWx0aXBsZSByb3dzIHBlciBhcnRpY2xlIGZvciBjb21wb3VuZHMpDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKGNvbXBvdW5kX2F0Y19ib29sZWFuID09ICJZZXMiKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShjb21wb3VuZF9hdGNfbGV2ZWxfMykgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gbigpKSAlPiUNCiAgZHBseXI6Om11dGF0ZShjb21wb3VuZF9hdGNfbGV2ZWxfMyA9IHN0cl90cmltKGNvbXBvdW5kX2F0Y19sZXZlbF8zKSkgJT4lDQogIHRpZHlyOjpzZXBhcmF0ZV9yb3dzKGNvbXBvdW5kX2F0Y19sZXZlbF8zLCBzZXAgPSAiOyIpICU+JSAjIGVhY2ggc3BwIGhhcyBtdWx0aXBsZSBoYWJpdGF0cyB0aGUgc3RyaW5nIG5lZWRzIHNwbGl0dGluZw0KICBkcGx5cjo6Z3JvdXBfYnkoY29tcG91bmRfYXRjX2xldmVsXzMpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IHN1bShuKSwNCiAgICAgICAgICAgICAgICAgcGVyY2VudCA9IHJvdW5kKG4vbl9jb21wb3VuZF9hdGMqMTAwLDEpLA0KICAgICAgICAgICAgICAgICBtZWFzdXJlID0gImNvbXBvdW5kcyIpICU+JSAjIG5vdyBhIHN1bSBmb3IgZWFjaCBoYWJpdGF0DQogIGFycmFuZ2UoZGVzYyhuKSkNCg0KY29tcG91bmRfQVRDX0wzX3N1bW1hcnkNCmBgYA0KDQpOb3cgd2Ugd2lsbCBtYWtlIGEgc2ltaWxhciBkYXRhIGZpbGUgdG8gbG9vayBhdCB0aGUgb3ZlcmFsbCB1c2UgaW4gdGhlIGRhdGFiYXNlIGF0IGVhY2ggQVRDIGxldmVsIDMNCg0KYGBge3J9DQpuX2RhdGFfYXRjIDwtIEVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIoY29tcG91bmRfYXRjX2Jvb2xlYW4gPT0gIlllcyIpICU+JSANCiAgbnJvdyguKQ0KDQpjb21wb3VuZF9BVENfTDNfZGF0YV9zdW1tYXJ5IDwtIEVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIoY29tcG91bmRfYXRjX2Jvb2xlYW4gPT0gIlllcyIpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KGNvbXBvdW5kX2F0Y19sZXZlbF8zKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBuKCkpICU+JQ0KICBkcGx5cjo6bXV0YXRlKGNvbXBvdW5kX2F0Y19sZXZlbF8zID0gc3RyX3RyaW0oY29tcG91bmRfYXRjX2xldmVsXzMpKSAlPiUNCiAgdGlkeXI6OnNlcGFyYXRlX3Jvd3MoY29tcG91bmRfYXRjX2xldmVsXzMsIHNlcCA9ICI7IikgJT4lICMgZWFjaCBzcHAgaGFzIG11bHRpcGxlIGhhYml0YXRzIHRoZSBzdHJpbmcgbmVlZHMgc3BsaXR0aW5nDQogIGRwbHlyOjpncm91cF9ieShjb21wb3VuZF9hdGNfbGV2ZWxfMykgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gc3VtKG4pLA0KICAgICAgICAgICAgICAgICBwZXJjZW50ID0gcm91bmQobi9uX2RhdGFfYXRjKjEwMCwxKSwNCiAgICAgICAgICAgICAgICAgbWVhc3VyZSA9ICJkYXRhIikgJT4lICMgbm93IGEgc3VtIGZvciBlYWNoIGhhYml0YXQNCiAgYXJyYW5nZShkZXNjKHBlcmNlbnQpKQ0KY29tcG91bmRfQVRDX0wzX2RhdGFfc3VtbWFyeQ0KYGBgDQpIZXJlIHdlIG1ha2UgYSBuZXcgY29sdW1uIGNhbGxlZCB2YWx1ZSB3aGVyZSB3ZSBjb21iaW5lZCB0aGUgY291bnQgb2YgZGlzdGluY3QgY29tcG91bmRzIGFuZCBwcm9wb3J0aW9uIG9mIGRhdGENCg0KYGBge3J9DQpBVENfTDNfc3VtbWFyeSA8LSBjb21wb3VuZF9BVENfTDNfc3VtbWFyeSAlPiUgDQogIHJiaW5kKC4sIGNvbXBvdW5kX0FUQ19MM19kYXRhX3N1bW1hcnkpICU+JSANCiAgZHBseXI6Om11dGF0ZSh2YWx1ZSA9IGlmX2Vsc2UobWVhc3VyZSA9PSAiY29tcG91bmRzIiwgbiwgcGVyY2VudCkpDQpgYGANCg0KDQpUaGlzIHBsb3Qgc2hvd3MgdGhlIG51bWJlciBvZiBkaWZmZXJlbnQgY29tcG91bmRzIGluIGVhY2ggQVRDIGNsYXNzaWZpY2F0aW9uIGFzIHdlbGwgYXMgdGhlIHRvdGFsIHByb3BvcnRpb24gb2YgZGF0YSBpdCBtYWtlcyB1cC4gVGhpcyBpcyBkb25lIGZvciBvbmx5IHRoZSAxNSBtb3N0IGNvbW1vbmx5IHVzZWQgZ3JvdXBzLiANCg0KYGBge3J9DQptZWFzdXJlX2NvbG91cl90aGVtZSA8LSBjKCJibGFjayIsICJncmV5IikgIyBNYWtpbmcgY29sb3VyIHRoZW1lIHRvIGFwcGx5IHRvIHBsb3QNCg0KIyBNYWtpbmcgYSBsaXN0IG9mIGFjdCBuYW1lcyBpbiB0aGUgb3JkZXIgdGhhdCB3ZSB3YW50IHRoZW0gaW4gdGhlIHBsb3QgDQpsZXZlbF8zX29yZGVyX3RvcF8xNSA8LSBBVENfTDNfc3VtbWFyeSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIobWVhc3VyZSA9PSAiZGF0YSIpICU+JSANCiAgZHBseXI6OmFycmFuZ2UoZGVzYyh2YWx1ZSkpICU+JSANCiAgZHBseXI6OnNsaWNlKDE6MTUpICU+JSANCiAgZHBseXI6OmFycmFuZ2UoZGVzYyh2YWx1ZSkpICU+JQ0KICBkcGx5cjo6cHVsbChjb21wb3VuZF9hdGNfbGV2ZWxfMykNCg0KIyBNYWtpbmcgdGhlIHBsb3QNCmF0Y19sZXZlbF8zX2ZpZyA8LSBBVENfTDNfc3VtbWFyeSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIoY29tcG91bmRfYXRjX2xldmVsXzMgJWluJSBsZXZlbF8zX29yZGVyX3RvcF8xNSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKGNvbXBvdW5kX2F0Y19sZXZlbF8zID0gZmFjdG9yKGNvbXBvdW5kX2F0Y19sZXZlbF8zLCBsZXZlbHMgPSBsZXZlbF8zX29yZGVyX3RvcF8xNSkpICU+JSANCiAgZ2dwbG90KGFlcyh4PWNvbXBvdW5kX2F0Y19sZXZlbF8zLCB5PXZhbHVlLCBmaWxsID0gbWVhc3VyZSwgY29sb3VyID0gbWVhc3VyZSwgDQogICAgICAgICAgICAgZ3JvdXAgPSBtZWFzdXJlKSkgKw0KICBnZW9tX2NvbChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMSksIHdpZHRoID0gMC4yLCBjb2xvdXIgPSBOQSwpICsNCiAgZ2VvbV9wb2ludChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMSksIHNpemUgPSAzKSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSB2YWx1ZSksIHZqdXN0PS0wLjYsIHNpemU9My41LCBwb3NpdGlvbiA9ICBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDEpKSArDQogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gbWVhc3VyZV9jb2xvdXJfdGhlbWUsIG5hbWUgPSAiVmFsdWUgdHlwZSIsDQogICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiQ29tcG91bmRzIChuKSIsICJQZXJjZW50YWdlIG9mIGRhdGEiKSkgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBtZWFzdXJlX2NvbG91cl90aGVtZSwgbmFtZSA9ICJWYWx1ZSB0eXBlIiwNCiAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJDb21wb3VuZHMgKG4pIiwgIlBlcmNlbnRhZ2Ugb2YgZGF0YSIpKSArDQogIHNjYWxlX3lfY29udGludW91cygNCiAgICBuYW1lID0gIkRpc3RpbmN0IGNvbXBvdW5kcyIsDQogICAgbGltaXRzID0gYygwLCAzMCksICAgICAgICAgICAgICAgICAgICMgU2V0IHRoZSByYW5nZSBvZiB5LWF4aXMNCiAgICBicmVha3MgPSBjKDAsIDEwLCAyMCwgMzApLCAgICAgICAgICAgIyBTZXQgdGhlIGxhYmVscyBhdCAwLCAxMCwgMjAsIDMwDQogICAgc2VjLmF4aXMgPSBzZWNfYXhpcyh+IC4gLCBuYW1lID0gIlBlcmNlbnRhZ2Ugb2YgZGF0YWJhc2UiKSAjIEFkanVzdCBzY2FsaW5nIGlmIG5lZWRlZA0KICApICsNCiAgdGhlbWVfY2xhc3NpYygpICsNCiAgIGxhYnMoDQogICAgeCA9ICIiLA0KICAgIHkgPSAiIg0KICApICsNCiAgIHRoZW1lKA0KICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSwgICAgICAgICAgIyBDaGFuZ2UgeS1heGlzIGxhYmVscyBzaXplDQogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0PTEsIHNpemUgPSA4KSwgIyBDaGFuZ2UgeC1heGlzIGxhYmVscyBvcmllbnRhdGlvbg0KICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLCAgICAgICAgICMgQ2hhbmdlIGxlZ2VuZCB0aXRsZSBzaXplIGlmIG5lZWRlZA0KICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCkgIA0KICAgKQ0KDQphdGNfbGV2ZWxfM19maWcNCmBgYA0KDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQ0Kc2V0d2QoZmlndXJlc19wYXRoKQ0KZ2dzYXZlKCJhdGNfbGV2ZWxfM19maWcucGRmIiwgcGxvdCA9IGF0Y19sZXZlbF8zX2ZpZywgd2lkdGggPSAxMCwgaGVpZ2h0ID0gNSkNCmBgYA0KDQoNCiMjIDEzLjMgTW9zdCBjb21tb24gY29tcG91bmRzIA0KDQpPdmVyYWxsIHRoZSBtb3N0IGNvbW1vbiBjb21wb3VuZHMgYXJlIEZsdW94ZXRpbmUsIERpYXplcGFtIGFuZCAxNy1hbHBoYS1ldGhpbnlsZXN0cmFkaW9sDQoNCmBgYHtyfQ0Kbl9yb3cgPC0gRUlQQUFCX2RhdGFiYXNlICU+JSANCiAgbnJvdyguKQ0KDQpjb21wb3VuZF91c2UgPC0gRUlQQUFCX2RhdGFiYXNlICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KGNvbXBvdW5kX25hbWUpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IG4oKSkgJT4lDQogIGRwbHlyOjptdXRhdGUocHJvcCA9IG4vbl9yb3cpICU+JQ0KICBhcnJhbmdlKGRlc2MocHJvcCkpDQoNCmNvbXBvdW5kX3VzZQ0KYGBgDQpMZXQncyBzZWUgd2hhdCB0aGUgbnVtYmVycyBhcmUgZm9yIGVhY2ggbW90aXZhdGlvbiwgYnV0IGxldCdzIGFsc28gbWFpbnRhaW4gdGhlIG92ZXJhbGwgbnVtYmVycyBzbyB3ZSBjYW4gYWRkIGl0IHRvIHRoZSBmaWd1cmUNCg0KYGBge3J9DQpuX3JvdyA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lIA0KICBucm93KC4pDQoNCmNvbXBvdW5kX3VzZV9tb3RpdmF0aW9uIDwtIEVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uLCBjb21wb3VuZF9uYW1lKSAlPiUgDQogIGRwbHlyOjpzdW1tYXJpc2UobiA9IG4oKSwgLmdyb3VwcyA9ICdkcm9wJykgJT4lDQogIHRpZHlyOjpjb21wbGV0ZShjb21wb3VuZF9uYW1lLCBzdHVkeV9tb3RpdmF0aW9uLCBmaWxsID0gbGlzdChuID0gMCkpICMgTWFraW5nIHN1cmUgd2UgaGF2ZSBhIGNvbXBsZXRlIGRhdGFmcmFtZQ0KDQpjb21wb3VuZF91c2VfbW90aXZhdGlvbiA8LSBjb21wb3VuZF91c2UgJT4lIA0KICBkcGx5cjo6c2VsZWN0KC1wcm9wKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoc3R1ZHlfbW90aXZhdGlvbiA9ICJBbGwiKSAlPiUgDQogIHJiaW5kKC4sIGNvbXBvdW5kX3VzZV9tb3RpdmF0aW9uKQ0KDQpjb21wb3VuZF91c2VfbW90aXZhdGlvbg0KYGBgDQoNClRoZSB0b3AgMTAgYmFzZWQgb24gZWFjaCBzdHVkeSBtb3RpdmF0aW9uIGFzIHdlbGwgYXMgdGhlIG92ZXJhbGwgdG90YWwNCg0KYGBge3J9DQp0b3BfMTBfY29tcF9hbGxfZmlnIDwtIGNvbXBvdW5kX3VzZV9tb3RpdmF0aW9uICU+JSANCiAgZHBseXI6OmZpbHRlcihzdHVkeV9tb3RpdmF0aW9uID09ICJBbGwiKSAlPiUgDQogIGRwbHlyOjphcnJhbmdlKGRlc2MobikpICU+JSANCiAgZHBseXI6OnNsaWNlKDE6MTApICU+JSANCiAgZHBseXI6Om11dGF0ZShjb21wb3VuZF9uYW1lID0gZmN0X3Jlb3JkZXIoY29tcG91bmRfbmFtZSwgbikpICU+JSANCiAgZ2dwbG90KGFlcyh4PWNvbXBvdW5kX25hbWUsIHk9bikpICsNCiAgZ2VvbV9jb2wod2lkdGggPSAwLjEsIGNvbG91ciA9IE5BLCBmaWxsID0gImdyZXkiKSArDQogIGdlb21fcG9pbnQoc2l6ZSA9IDMsIGNvbG91ciA9ICJncmV5IiwgZmlsbCA9ICJncmV5IikgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gbiksIGhqdXN0PS0wLjYsIHNpemU9My41LCBjb2xvcj0iYmxhY2siKSArDQogIGNvb3JkX2ZsaXAoKSArDQogIHRoZW1lX2NsYXNzaWMoKSArDQogICBsYWJzKA0KICAgICB0aXRsZSA9ICJBbGwiLA0KICAgIHggPSAiIiwNCiAgICB5ID0gIlRvdGFsIHVzZSBpbiB0aGUgZGF0YWJhc2UiDQogICkgKw0KICAgdGhlbWUoDQogICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDExKQ0KICAgKQ0KDQoNCnRvcF8xMF9jb21wX2Vudl9maWcgPC0gY29tcG91bmRfdXNlX21vdGl2YXRpb24gJT4lIA0KICBkcGx5cjo6ZmlsdGVyKHN0dWR5X21vdGl2YXRpb24gPT0gIkVudmlyb25tZW50YWwiKSAlPiUgDQogIGRwbHlyOjphcnJhbmdlKGRlc2MobikpICU+JSANCiAgZHBseXI6OnNsaWNlKDE6MTApICU+JSANCiAgZHBseXI6Om11dGF0ZShjb21wb3VuZF9uYW1lID0gZmN0X3Jlb3JkZXIoY29tcG91bmRfbmFtZSwgbikpICU+JSANCiAgZ2dwbG90KGFlcyh4PWNvbXBvdW5kX25hbWUsIHk9bikpICsNCiAgZ2VvbV9jb2wod2lkdGggPSAwLjEsIGNvbG91ciA9IE5BLCBmaWxsID0gIiM2MEJENkMiKSArDQogIGdlb21fcG9pbnQoc2l6ZSA9IDMsIGNvbG91ciA9ICIjNjBCRDZDIiwgZmlsbCA9ICIjNjBCRDZDIikgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gbiksIGhqdXN0PS0wLjYsIHNpemU9My41LCBjb2xvcj0iYmxhY2siKSArDQogIGNvb3JkX2ZsaXAoKSArDQogIHRoZW1lX2NsYXNzaWMoKSArDQogICBsYWJzKA0KICAgICB0aXRsZSA9ICJFbnZpcm9ubWVudGFsIiwNCiAgICB4ID0gIiIsDQogICAgeSA9ICJUb3RhbCB1c2UgaW4gdGhlIGRhdGFiYXNlIg0KICApICsNCiAgIHRoZW1lKA0KICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMSkNCiAgICkNCg0KDQp0b3BfMTBfY29tcF9tZWRfZmlnIDwtIGNvbXBvdW5kX3VzZV9tb3RpdmF0aW9uICU+JSANCiAgZHBseXI6OmZpbHRlcihzdHVkeV9tb3RpdmF0aW9uID09ICJNZWRpY2FsIikgJT4lIA0KICBkcGx5cjo6YXJyYW5nZShkZXNjKG4pKSAlPiUgDQogIGRwbHlyOjpzbGljZSgxOjEwKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoY29tcG91bmRfbmFtZSA9IGZjdF9yZW9yZGVyKGNvbXBvdW5kX25hbWUsIG4pKSAlPiUgDQogIGdncGxvdChhZXMoeD1jb21wb3VuZF9uYW1lLCB5PW4pKSArDQogIGdlb21fY29sKHdpZHRoID0gMC4xLCBjb2xvdXIgPSBOQSwgZmlsbCA9ICIjRDM1OUExIikgKw0KICBnZW9tX3BvaW50KHNpemUgPSAzLCBjb2xvdXIgPSAiI0QzNTlBMSIsIGZpbGwgPSAiI0QzNTlBMSIpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IG4pLCBoanVzdD0tMC42LCBzaXplPTMuNSwgY29sb3I9ImJsYWNrIikgKw0KICBjb29yZF9mbGlwKCkgKw0KICB0aGVtZV9jbGFzc2ljKCkgKw0KICAgbGFicygNCiAgICAgdGl0bGUgPSAiTWVkaWNhbCIsDQogICAgeCA9ICIiLA0KICAgIHkgPSAiVG90YWwgdXNlIGluIHRoZSBkYXRhYmFzZSINCiAgKSArDQogICB0aGVtZSgNCiAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTEpDQogICApDQoNCnRvcF8xMF9jb21wX2Jhc2VfZmlnIDwtIGNvbXBvdW5kX3VzZV9tb3RpdmF0aW9uICU+JSANCiAgZHBseXI6OmZpbHRlcihzdHVkeV9tb3RpdmF0aW9uID09ICJCYXNpYyByZXNlYXJjaCIpICU+JSANCiAgZHBseXI6OmFycmFuZ2UoZGVzYyhuKSkgJT4lIA0KICBkcGx5cjo6c2xpY2UoMToxMCkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKGNvbXBvdW5kX25hbWUgPSBmY3RfcmVvcmRlcihjb21wb3VuZF9uYW1lLCBuKSkgJT4lIA0KICBnZ3Bsb3QoYWVzKHg9Y29tcG91bmRfbmFtZSwgeT1uKSkgKw0KICBnZW9tX2NvbCh3aWR0aCA9IDAuMSwgY29sb3VyID0gTkEsIGZpbGwgPSAiIzNDODJDNCIpICsNCiAgZ2VvbV9wb2ludChzaXplID0gMywgY29sb3VyID0gIiMzQzgyQzQiLCBmaWxsID0gIiMzQzgyQzQiKSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBuKSwgaGp1c3Q9LTAuNiwgc2l6ZT0zLjUsIGNvbG9yPSJibGFjayIpICsNCiAgY29vcmRfZmxpcCgpICsNCiAgdGhlbWVfY2xhc3NpYygpICsNCiAgIGxhYnMoDQogICAgIHRpdGxlID0gIkJhc2ljIFJlc2VhcmNoIiwNCiAgICB4ID0gIiIsDQogICAgeSA9ICJUb3RhbCB1c2UgaW4gdGhlIGRhdGFiYXNlIg0KICApICsNCiAgIHRoZW1lKA0KICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMSkNCiAgICAgKQ0KYGBgDQoNCkhlcmUgYXJlIHRoZSByZXN1bHRpbmcgZmlndXJlcyANCg0KYGBge3IsIGZpZy53aWR0aD0yLjUsIGZpZy5oZWlnaHQ9NX0NCnRvcF8xMF9jb21wX2FsbF9maWcNCnRvcF8xMF9jb21wX2Vudl9maWcNCnRvcF8xMF9jb21wX21lZF9maWcNCnRvcF8xMF9jb21wX2Jhc2VfZmlnDQpgYGANCg0KU2F2aW5nIGFzIFBERnMNCg0KYGBge3IsIHdhcm5pbmc9RkFMU0V9DQpzZXR3ZChmaWd1cmVzX3BhdGgpDQpnZ3NhdmUoImNvbXBfdG9wXzEwX2NvbXBfYWxsX2ZpZy5wZGYiLCBwbG90ID0gdG9wXzEwX2NvbXBfYWxsX2ZpZywgd2lkdGggPSA1LCBoZWlnaHQgPSAxMCkNCmdnc2F2ZSgiY29tcF90b3BfMTBfY29tcF9lbnZfZmlnLnBkZiIsIHBsb3QgPSB0b3BfMTBfY29tcF9lbnZfZmlnLCB3aWR0aCA9IDUsIGhlaWdodCA9IDEwKQ0KZ2dzYXZlKCJjb21wX3RvcF8xMF9jb21wX21lZF9maWcucGRmIiwgcGxvdCA9IHRvcF8xMF9jb21wX21lZF9maWcsIHdpZHRoID0gNSwgaGVpZ2h0ID0gMTApDQpnZ3NhdmUoImNvbXBfdG9wXzEwX2NvbXBfYmFzZV9maWcucGRmIiwgcGxvdCA9IHRvcF8xMF9jb21wX2Jhc2VfZmlnLCB3aWR0aCA9IDUsIGhlaWdodCA9IDEwKQ0KYGBgDQoNCmBgYHtyfQ0KY29tcG91bmRfdXNlX21vdGl2YXRpb24gJT4lIA0KICBkcGx5cjo6ZmlsdGVyKGNvbXBvdW5kX25hbWUgPT0gIjE3LWFscGhhLWV0aGlueWxlc3RyYWRpb2wiKQ0KYGBgDQoNCiMjIDEzLjQgTWl4dHVyZXMNCg0KSXQgd2FzIHJlY29yZGVkIHdoZXRoZXIgdGhlIGFuaW1hbHMgd2VyZSBhbHNvIGV4cG9zZWQgdG8gY29tcG91bmQgbWl4dHVyZXMNCg0KYGBge3J9DQpFSVBBQUJfZGF0YWJhc2UgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoYXJ0aWNsZV9pZCkgJT4lIA0KICBkcGx5cjo6c2FtcGxlX24oMSkgJT4lIA0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobWl4dHVyZV95ZXMgPSBzdW0oY29tcG9uZF9taXh0dXJlID09ICJZZXMiLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgICAgICAgICBtaXh0dXJlX25vID0gc3VtKGNvbXBvbmRfbWl4dHVyZSA9PSAiTm8iLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgICAgICAgICBtaXh0dXJlX3BlcmNlbnQgPSAobWl4dHVyZV95ZXMvbWl4dHVyZV9ubykqMTAwDQogICAgICAgICAgICAgICAgICkNCmBgYA0KDQpNZWRpY2FsIGFydGljbGVzIGhhdmUgYSBtdWNoIGhpZ2hlciB1c2Ugb2YgbWl4dHVyZXMNCg0KYGBge3J9DQpFSVBBQUJfZGF0YWJhc2UgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoYXJ0aWNsZV9pZCkgJT4lIA0KICBkcGx5cjo6c2FtcGxlX24oMSkgJT4lIA0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHN0dWR5X21vdGl2YXRpb24pICU+JSANCiAgZHBseXI6OnJlZnJhbWUobWl4dHVyZV95ZXMgPSBzdW0oY29tcG9uZF9taXh0dXJlID09ICJZZXMiLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgICAgICAgICBtaXh0dXJlX25vID0gc3VtKGNvbXBvbmRfbWl4dHVyZSA9PSAiTm8iLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgICAgICAgICBtaXh0dXJlX3BlcmNlbnQgPSByb3VuZCgobWl4dHVyZV95ZXMvbWl4dHVyZV9ubykqMTAwLDEpDQogICAgICAgICAgICAgICAgICkNCmBgYA0KDQojIyAxMy42IEV4cG9zdXJlIHJvdXRlDQoNCkRhdGEgb24gdGhlIG1ldGhvZCBvZiBleHBvc3VyZSB3YXMgYWxzbyBleHRyYWN0ZWQNCg0KYGBge3J9DQpucm93IDwtIEVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIG5yb3coLikNCg0KRUlQQUFCX2RhdGFiYXNlICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KGNvbXBvdW5kX2V4cG9zZV9yb3V0ZSkgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gbigpLA0KICAgICAgICAgICAgICAgICBwZXJjZW50ID0gcm91bmQoKG4vbnJvdykqMTAwLDEpDQopDQpgYGANCg0KIyMgMTMuNyBFeHBvc3VyZSBsZW5ndGgNCg0KVGhlIGRhdGFiYXNlIGhhcyBib3RoIHRoZSBtaW5pbXVtIGFuZCBtYXhpbXVtIGR1cmF0aW9uIG9mIGV4cG9zdXJlIHByaW9yIHRvIGJlaGF2aW91cmFsIG1lYXN1cmUNCihjb21wb3VuZF9taW5fZHVyYXRpb25fZXhwb3N1cmUgYW5kIGNvbXBvdW5kX21heF9kdXJhdGlvbl9leHBvc3VyZSkuIEhlcmUgd2Ugd2lsbCBmb2N1cyBvbiB0aGUgbWF4aW11bSBkdXJhdGlvbg0KDQpUaGVzZSBhcmUgdGhlIGRpZmZlcmVudCBjYXRlZ29yaWVzIG9mIGV4cG9zdXJlIGxlbmd0aA0KDQpgYGB7cn0NCkVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIGRwbHlyOjpkaXN0aW5jdChjb21wb3VuZF9tYXhfZHVyYXRpb25fZXhwb3N1cmUpDQpgYGANClNvbWUgYXJ0aWNsZXMgZGlkIG5vdCByZXBvcnQgdGhlIGV4cG9zdXJlIGR1cmF0aW9uIGF0IGFsbCwgb3IgaW4gc3VmZmljaWVudCBkZXRhaWwgdG8gZXh0cmFjdC4gDQoNCkluIHRvdGFsIHRoaXMgb2NjdXJyZWQgaW4gMTA4IGNhc2VzDQoNCmBgYHtyfQ0KRUlQQUFCX2RhdGFiYXNlICU+JSANCiAgZHBseXI6OmZpbHRlcihjb21wb3VuZF9taW5fZHVyYXRpb25fZXhwb3N1cmUgPT0gIk5vdCBzdGF0ZWQiIHwgY29tcG91bmRfbWF4X2R1cmF0aW9uX2V4cG9zdXJlID09ICJOb3Qgc3RhdGVkIikgJT4lIA0KICBucm93KC4pDQpgYGANCg0KDQpgYGB7cn0NCmV4cG9zdXJlX2R1cmF0aW9uX29yZGVyIDwtIGMoIkxlc3MgdGhhbiA2IGhvdXJzIiwgIjYgdG8gMjQgaG91cnMiLCAiMSB0byAzIGRheXMiLCAiMyB0byA4IGRheXMiLCAiOCB0byAxNSBkYXlzIiwgIjE1IHRvIDIyIGRheXMiLCAiMjIgdG8gMjkgZGF5cyIsICIxIHRvIDMgbW9udGhzIiwgIjMgdG8gNiBtb250aHMiLCAiTGlmZXRpbWUiLCAiVHJhbnNnZW5lcmF0aW9uYWwiLCAiTXVsdGlnZW5lcmF0aW9uYWwiKQ0KDQpucm93IDwtIEVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIoY29tcG91bmRfbWF4X2R1cmF0aW9uX2V4cG9zdXJlICE9ICJOb3Qgc3RhdGVkIikgJT4lIA0KICBucm93KC4pDQoNCmV4cG9zdXJlX2R1cmF0aW9uX3N1bW1hcnkgPC0gRUlQQUFCX2RhdGFiYXNlICU+JSANCiAgZHBseXI6OmZpbHRlcihjb21wb3VuZF9tYXhfZHVyYXRpb25fZXhwb3N1cmUgIT0gIk5vdCBzdGF0ZWQiKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShjb21wb3VuZF9tYXhfZHVyYXRpb25fZXhwb3N1cmUpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IG4oKSwNCiAgICAgICAgICAgICAgICAgcGVyY2VudCA9IHJvdW5kKChuL25yb3cpKjEwMCwxKQ0KICAgICAgICAgICAgICAgICApICU+JSANCiAgZHBseXI6Om11dGF0ZShjb21wb3VuZF9tYXhfZHVyYXRpb25fZXhwb3N1cmUgPSAgZmFjdG9yKGNvbXBvdW5kX21heF9kdXJhdGlvbl9leHBvc3VyZSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBleHBvc3VyZV9kdXJhdGlvbl9vcmRlcikpICU+JSANCiAgZHBseXI6OmFycmFuZ2UoY29tcG91bmRfbWF4X2R1cmF0aW9uX2V4cG9zdXJlKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoc3R1ZHlfbW90aXZhdGlvbiA9ICJBbGwiKQ0KDQpleHBvc3VyZV9kdXJhdGlvbl9zdW1tYXJ5DQpgYGANCg0KYGBge3J9DQpleHBvc3VyZV9kdXJhdGlvbl9vcmRlciA8LSBjKCJMZXNzIHRoYW4gNiBob3VycyIsICI2IHRvIDI0IGhvdXJzIiwgIjEgdG8gMyBkYXlzIiwgIjMgdG8gOCBkYXlzIiwgIjggdG8gMTUgZGF5cyIsICIxNSB0byAyMiBkYXlzIiwgIjIyIHRvIDI5IGRheXMiLCAiMSB0byAzIG1vbnRocyIsICIzIHRvIDYgbW9udGhzIiwgIkxpZmV0aW1lIiwgIlRyYW5zZ2VuZXJhdGlvbmFsIiwgIk11bHRpZ2VuZXJhdGlvbmFsIikNCg0KDQpleHBvc3VyZV9kdXJhdGlvbl9tb3RpdmF0aW9uX3N1bW1hcnkgPC0gRUlQQUFCX2RhdGFiYXNlICU+JSANCiAgZHBseXI6OmZpbHRlcihjb21wb3VuZF9tYXhfZHVyYXRpb25fZXhwb3N1cmUgIT0gIk5vdCBzdGF0ZWQiKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShjb21wb3VuZF9tYXhfZHVyYXRpb25fZXhwb3N1cmUsIHN0dWR5X21vdGl2YXRpb24pICU+JSANCiAgZHBseXI6OnN1bW1hcmlzZShuID0gbigpLCAuZ3JvdXBzID0gJ2Ryb3AnKSAlPiUgDQogIHRpZHlyOjpjb21wbGV0ZShjb21wb3VuZF9tYXhfZHVyYXRpb25fZXhwb3N1cmUsIHN0dWR5X21vdGl2YXRpb24sIGZpbGwgPSBsaXN0KG4gPSAwKSkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHRvdGFsX21vdGl2YXRpb24gPSBzdW0obikpICU+JSANCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjptdXRhdGUocGVyY2VudCA9IHJvdW5kKChuL3RvdGFsX21vdGl2YXRpb24pKjEwMCwxKSkgJT4lDQogIGRwbHlyOjpzZWxlY3QoLXRvdGFsX21vdGl2YXRpb24pDQoNCmV4cF9kdXJhdGlvbl9tb3RpdmF0aW9uX3N1bW1hcnkgPC0gZXhwb3N1cmVfZHVyYXRpb25fbW90aXZhdGlvbl9zdW1tYXJ5ICU+JSANCiAgcmJpbmQoZXhwb3N1cmVfZHVyYXRpb25fc3VtbWFyeSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKGNvbXBvdW5kX21heF9kdXJhdGlvbl9leHBvc3VyZSA9ICBmYWN0b3IoY29tcG91bmRfbWF4X2R1cmF0aW9uX2V4cG9zdXJlLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IHJldihleHBvc3VyZV9kdXJhdGlvbl9vcmRlcikpDQogICAgICAgICAgICAgICAgKSAlPiUgDQogIGRwbHlyOjphcnJhbmdlKGRlc2MoY29tcG91bmRfbWF4X2R1cmF0aW9uX2V4cG9zdXJlKSkNCg0KZXhwX2R1cmF0aW9uX21vdGl2YXRpb25fc3VtbWFyeQ0KYGBgDQoNCmBgYHtyfQ0KZXhwX2R1cmF0aW9uX2FsbF9maWcgPC0gZXhwX2R1cmF0aW9uX21vdGl2YXRpb25fc3VtbWFyeSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIoc3R1ZHlfbW90aXZhdGlvbiA9PSAiQWxsIikgJT4lDQogIGdncGxvdChhZXMoeD1jb21wb3VuZF9tYXhfZHVyYXRpb25fZXhwb3N1cmUsIHk9cGVyY2VudCkpICsNCiAgZ2VvbV9jb2wod2lkdGggPSAwLjEsIGNvbG91ciA9IE5BLCBmaWxsID0gImdyZXkiKSArDQogIGdlb21fcG9pbnQoc2l6ZSA9IDMsIGNvbG91ciA9ICJncmV5IiwgZmlsbCA9ICJncmV5IikgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGVyY2VudCksIHZqdXN0PS0wLjYsIHNpemU9My41LCBjb2xvcj0iYmxhY2siKSArDQogIHRoZW1lX2NsYXNzaWMoKSArDQogIGNvb3JkX2ZsaXAoKSArDQogICBsYWJzKA0KICAgICB0aXRsZSA9ICJBbGwiLA0KICAgIHggPSAiIiwNCiAgICB5ID0gIlRvdGFsIHBlcmNlbnRhZ2UiDQogICkgKw0KICAgdGhlbWUoDQogICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDExKQ0KICAgKQ0KDQoNCmV4cF9kdXJhdGlvbl9lbnZfZmlnIDwtIGV4cF9kdXJhdGlvbl9tb3RpdmF0aW9uX3N1bW1hcnkgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKHN0dWR5X21vdGl2YXRpb24gPT0gIkVudmlyb25tZW50YWwiKSAlPiUNCiAgZ2dwbG90KGFlcyh4PWNvbXBvdW5kX21heF9kdXJhdGlvbl9leHBvc3VyZSwgeT1wZXJjZW50KSkgKw0KICBnZW9tX2NvbCh3aWR0aCA9IDAuMSwgY29sb3VyID0gTkEsIGZpbGwgPSAiIzYwQkQ2QyIpICsNCiAgZ2VvbV9wb2ludChzaXplID0gMywgY29sb3VyID0gIiM2MEJENkMiLCBmaWxsID0gIiM2MEJENkMiKSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBwZXJjZW50KSwgdmp1c3Q9LTAuNiwgc2l6ZT0zLjUsIGNvbG9yPSJibGFjayIpICsNCiAgdGhlbWVfY2xhc3NpYygpICsNCiAgY29vcmRfZmxpcCgpICsNCiAgIGxhYnMoDQogICAgIHRpdGxlID0gIkVudmlyb25tZW50YWwiLA0KICAgIHggPSAiIiwNCiAgICB5ID0gIlRvdGFsIHBlcmNlbnRhZ2UiDQogICkgKw0KICAgdGhlbWUoDQogICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDExKQ0KICAgKQ0KDQpleHBfZHVyYXRpb25fbWVkX2ZpZyA8LSBleHBfZHVyYXRpb25fbW90aXZhdGlvbl9zdW1tYXJ5ICU+JSANCiAgZHBseXI6OmZpbHRlcihzdHVkeV9tb3RpdmF0aW9uID09ICJNZWRpY2FsIikgJT4lDQogIGdncGxvdChhZXMoeD1jb21wb3VuZF9tYXhfZHVyYXRpb25fZXhwb3N1cmUsIHk9cGVyY2VudCkpICsNCiAgZ2VvbV9jb2wod2lkdGggPSAwLjEsIGNvbG91ciA9IE5BLCBmaWxsID0gIiNEMzU5QTEiKSArDQogIGdlb21fcG9pbnQoc2l6ZSA9IDMsIGNvbG91ciA9ICIjRDM1OUExIiwgZmlsbCA9ICIjRDM1OUExIikgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGVyY2VudCksIHZqdXN0PS0wLjYsIHNpemU9My41LCBjb2xvcj0iYmxhY2siKSArDQogIHRoZW1lX2NsYXNzaWMoKSArDQogIGNvb3JkX2ZsaXAoKSArDQogICBsYWJzKA0KICAgICB0aXRsZSA9ICJNZWRpY2FsIiwNCiAgICB4ID0gIiIsDQogICAgeSA9ICJUb3RhbCBwZXJjZW50YWdlIg0KICApICsNCiAgIHRoZW1lKA0KICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMSkNCiAgICkNCg0KDQpleHBfZHVyYXRpb25fYmFzZV9maWcgPC0gZXhwX2R1cmF0aW9uX21vdGl2YXRpb25fc3VtbWFyeSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIoc3R1ZHlfbW90aXZhdGlvbiA9PSAiQmFzaWMgcmVzZWFyY2giKSAlPiUNCiAgZ2dwbG90KGFlcyh4PWNvbXBvdW5kX21heF9kdXJhdGlvbl9leHBvc3VyZSwgeT1wZXJjZW50KSkgKw0KICBnZW9tX2NvbCh3aWR0aCA9IDAuMSwgY29sb3VyID0gTkEsIGZpbGwgPSAiIzNDODJDNCIpICsNCiAgZ2VvbV9wb2ludChzaXplID0gMywgY29sb3VyID0gIiMzQzgyQzQiLCBmaWxsID0gIiMzQzgyQzQiKSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBwZXJjZW50KSwgdmp1c3Q9LTAuNiwgc2l6ZT0zLjUsIGNvbG9yPSJibGFjayIpICsNCiAgdGhlbWVfY2xhc3NpYygpICsNCiAgY29vcmRfZmxpcCgpICsNCiAgIGxhYnMoDQogICAgIHRpdGxlID0gIkJhc2ljIHJlc2VhcmNoIiwNCiAgICB4ID0gIiIsDQogICAgeSA9ICJUb3RhbCBwZXJjZW50YWdlIg0KICApICsNCiAgIHRoZW1lKA0KICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMSkNCiAgICkNCmBgYA0KDQoNCmBgYHtyLCBmaWcud2lkdGg9OC4zLzMsIGZpZy5oZWlnaHQ9MTEuNy8zfQ0KZXhwX2R1cmF0aW9uX2FsbF9maWcNCmV4cF9kdXJhdGlvbl9lbnZfZmlnDQpleHBfZHVyYXRpb25fbWVkX2ZpZw0KZXhwX2R1cmF0aW9uX2Jhc2VfZmlnDQpgYGANCg0KYGBge3IsIHdhcm5pbmc9RkFMU0V9DQpzZXR3ZChmaWd1cmVzX3BhdGgpDQpnZ3NhdmUoImNvbXBfZXhwX2R1cmF0aW9uX2FsbF9maWcucGRmIiwgcGxvdCA9IGV4cF9kdXJhdGlvbl9hbGxfZmlnLCB3aWR0aCA9IDguMy8zLCBoZWlnaHQgPSAxMS43LzMpDQpnZ3NhdmUoImNvbXBfZXhwX2R1cmF0aW9uX2Vudl9maWcucGRmIiwgcGxvdCA9IGV4cF9kdXJhdGlvbl9lbnZfZmlnLCB3aWR0aCA9IDguMy8zLCBoZWlnaHQgPSAxMS43LzMpDQpnZ3NhdmUoImNvbXBfZXhwX2R1cmF0aW9uX21lZF9maWcucGRmIiwgcGxvdCA9IGV4cF9kdXJhdGlvbl9tZWRfZmlnLCB3aWR0aCA9IDguMy8zLCBoZWlnaHQgPSAxMS43LzMpDQpnZ3NhdmUoImNvbXBfZXhwX2R1cmF0aW9uX2Jhc2VfZmlnLnBkZiIsIHBsb3QgPSBleHBfZHVyYXRpb25fYmFzZV9maWcsIHdpZHRoID0gOC4zLzMsIGhlaWdodCA9IDExLjcvMykNCmBgYA0KDQojIyAxMy44IE51bWJlciBvZiBkb3Nlcw0KDQpIZXJlIEkgd2lsbCBsb29rIGF0IHRoZSBudW1iZXIgb2YgZG9zZXMgdXNlZC4gVGhpcyB3YXMgbWVhc3N1cmVkIGFzIHRoZSB0b3RhbCB0cmVhdG1lbnRzIChpLmUuIGluY3VsZGluZyBjb250cm9sKSwgc28gaWYgd2Ugd2FudCB0byBrbm93IHRoZSBudW1iZXIgb2YgZG9zZXMgZm9yIHRoZSBjb21wb3VuZCB3ZSBuZWVkIHRvIHN1YnRyYWN0IDEuIEkgaGF2ZSBkb25lIHRoaXMgYmVsb3cuDQoNCmBgYHtyfQ0Kbl9kb3Nlc19zdW1tYXJ5IDwtICBFSVBBQUJfZGF0YWJhc2UgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKCFpcy5uYShjb21wb3VuZF90cmVhdG1lbnRfbGV2ZWxzKSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKG5fZG9zZXMgPSBjb21wb3VuZF90cmVhdG1lbnRfbGV2ZWxzLTEpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KG5fZG9zZXMpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IG4oKSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHRvdGFsID0gc3VtKG4pLA0KICAgICAgICAgICAgICAgIHBlcmNlbnQgPSByb3VuZCgobi90b3RhbCkqMTAwLDEpLA0KICAgICAgICAgICAgICAgIHN0dWR5X21vdGl2YXRpb24gPSAiQWxsIikNCm5fZG9zZXNfc3VtbWFyeQ0KYGBgDQpMZXQncyBzZWUgaG93IG1hbnkgdXNlIG1vcmUgdGhlbiA1DQoNCmBgYHtyfQ0Kbl9kb3Nlc19zdW1tYXJ5ICU+JSANCiAgZHBseXI6OmZpbHRlcihuX2Rvc2VzID4gNSkgJT4lIA0KICBkcGx5cjo6c3VtbWFyaXNlKG92ZXJfNV9wZXJjZW50ID0gc3VtKHBlcmNlbnQpKQ0KYGBgDQoNCkxvb2tpbmcgYnkgc3R1ZHkgbW90aXZhdGlvbg0KDQpgYGB7cn0NCm5fZG9zZXNfbW90aXZhdGlvbl9zdW1tYXJ5IDwtICBFSVBBQUJfZGF0YWJhc2UgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKCFpcy5uYShjb21wb3VuZF90cmVhdG1lbnRfbGV2ZWxzKSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKG5fZG9zZXMgPSBjb21wb3VuZF90cmVhdG1lbnRfbGV2ZWxzLTEpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KG5fZG9zZXMsIHN0dWR5X21vdGl2YXRpb24pICU+JSANCiAgZHBseXI6OnN1bW1hcmlzZShuID0gbigpLCAuZ3JvdXBzID0gJ2Ryb3AnKSAlPiUNCiAgdGlkeXI6OmNvbXBsZXRlKG5fZG9zZXMsIHN0dWR5X21vdGl2YXRpb24sIGZpbGwgPSBsaXN0KG4gPSAwKSkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHRvdGFsID0gc3VtKG4pKSAlPiUgDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHBlcmNlbnQgPSByb3VuZCgobi90b3RhbCkqMTAwLDEpKSANCm5fZG9zZXNfbW90aXZhdGlvbl9zdW1tYXJ5DQpgYGANCg0KTWFraW5nIGEgcGxvdA0KICANCmBgYHtyfQ0KZG9zZV9vcmRlciA8LSBjKDE6MTIsICI+MTIiKQ0KDQpkb3Nlc19maWcgPC0gbl9kb3Nlc19tb3RpdmF0aW9uX3N1bW1hcnkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKG5fZG9zZXMgPSBhcy5jaGFyYWN0ZXIoaWZfZWxzZShuX2Rvc2VzPjEzLCAxMywgbl9kb3NlcykpLA0KICAgICAgICAgICAgICAgIG5fZG9zZXMgPSBpZl9lbHNlKG5fZG9zZXMgPT0gIjEzIiwgIj4xMiIsIG5fZG9zZXMpLA0KICAgICAgICAgICAgICAgIG5fZG9zZXMgPSBmYWN0b3Iobl9kb3NlcywgbGV2ZWxzID0gZG9zZV9vcmRlcikNCiAgICAgICAgICAgICAgICApJT4lIA0KICBnZ3Bsb3QoYWVzKHg9bl9kb3NlcywgeT1wZXJjZW50LCBjb2xvdXIgPSBzdHVkeV9tb3RpdmF0aW9uLCANCiAgICAgICAgICAgICBmaWxsID0gc3R1ZHlfbW90aXZhdGlvbiwgZ3JvdXAgPSBzdHVkeV9tb3RpdmF0aW9uKSkgKw0KICBnZW9tX3BvaW50KHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjgpLCBzaXplID0gMykgKw0KICBnZW9tX2xpbmUoc2l6ZSA9IDEpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHBlcmNlbnQpLCB2anVzdD0tMC42LCBzaXplPTMuNSwgY29sb3I9ImJsYWNrIikgKw0KICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IG1vdGl2YXRpb25fY29sb3VyX3RoZW1lLCBuYW1lID0gIlN0dWR5IG1vdGl2YXRpb24iKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IG1vdGl2YXRpb25fY29sb3VyX3RoZW1lLCBuYW1lID0gIlN0dWR5IG1vdGl2YXRpb24iKSArDQogIHRoZW1lX2NsYXNzaWMoKSArDQogIGZhY2V0X3dyYXAofnN0dWR5X21vdGl2YXRpb24pICsNCiAgdGhlbWUoDQogICAgbGVnZW5kLnBvc2l0aW9uID0gYygwLjgsIDAuOSksICMgUG9zaXRpb25pbmcgdGhlIGxlZ2VuZCBpbiB0aGUgdG9wLWxlZnQgY29ybmVyIHdpdGhpbiB0aGUgcGxvdA0KICAgIGxlZ2VuZC5qdXN0aWZpY2F0aW9uID0gYygwLCAxKSAjIEVuc3VyaW5nIHRoZSBsZWdlbmQgYm94IGFsaWducyBwcm9wZXJseSBhdCB0aGUgdG9wLWxlZnQgY29ybmVyDQogICAgKSArDQogICBsYWJzKA0KICAgIHggPSAiIiwNCiAgICB5ID0gIk51bWJlciBvZiBzdHVkaWVzIg0KICApICsNCiAgIHRoZW1lKCkNCg0KZG9zZXNfZmlnDQpgYGANCg0KDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQ0Kc2V0d2QoZmlndXJlc19wYXRoKQ0KZ2dzYXZlKCJjb21wX2Rvc2VzX2ZpZy5wZGYiLCBwbG90ID0gZG9zZXNfZmlnLCB3aWR0aCA9IDguMywgaGVpZ2h0ID0gMTEuNy8zKQ0KYGBgDQoNCg0KICMjIDkuOCBDb25jZW50cmF0aW9ucw0KDQpIZXJlIEkgd2lsbCBoYXZlIGEgbG9vayBhdCB0aGUgbWluIGFuZCBtYXggYW5kIHJhbmdlIG9mIGRvc2VzIHVzZWQgaW4gdGhlIGRhdGFiYXNlLiBGb3IgdGhlIE1TLCBJIGFtIGluY2x1ZGluZyBvbmx5IHN0dWRpZXMgdGhhdCByZXBvcnRlZCBpbiBhIG1hc3MgdG8gd2F0ZXIgdm9sdW1lIG1lYXN1cmUgc28gd2UgY2FuIGNvbXBhcmUgc3RhbmRhcmRpc2VkIHVuaXRlcyAodWcvTCkuIFRoaXMgd2FzIHRoZSBtb3N0IGNvbW1vbiByZXBvcnRpbmcgbWV0aG9kcyAoNjIlIG9mIGFsbCBkYXRhOyAxMDkwIHRvdGFsKS4NCg0KYGBge3J9DQpucm93IDwtIEVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIG5yb3coKQ0KDQpFSVBBQUJfZGF0YWJhc2UgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoY29tcG91bmRfbWluX2Rvc2VfdW5pdF9zdGQpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IG4oKSwNCiAgICAgICAgICAgICAgICAgcHJvcCA9IG4vbnJvdykgJT4lIA0KICBkcGx5cjo6YXJyYW5nZShkZXNjKG4pKQ0KYGBgDQoNClN1bW1hcnkgb2YgdGhlIG1pbmltdW0gY29uY2VudHJhdGlvbiB1c2VkICh3aGVyZSByZXBvcnRlZCBpbiBtYXNzIHRvIHZvbHVtZSkNCg0KYGBge3J9DQpFSVBBQUJfZGF0YWJhc2UgPC0gRUlQQUFCX2RhdGFiYXNlICU+JSANCiAgZHBseXI6Om11dGF0ZShyYW5nZSA9IGNvbXBvdW5kX21heF9kb3NlX3N0ZCAtIGNvbXBvdW5kX21pbl9kb3NlX3N0ZCkNCmBgYA0KDQoNCmBgYHtyfQ0KRUlQQUFCX2RhdGFiYXNlICU+JSANCiAgZHBseXI6OmZpbHRlcihjb21wb3VuZF9taW5fZG9zZV91bml0X3N0ZCA9PSAidWcvTCIsIGNvbXBvdW5kX21heF9kb3NlX3VuaXRfc3RkID09ICJ1Zy9MIikgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHJhbmdlID0gY29tcG91bmRfbWF4X2Rvc2Vfc3RkIC0gY29tcG91bmRfbWluX2Rvc2Vfc3RkKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG1lZGlhbl9taW4gPSAgbWVkaWFuKGNvbXBvdW5kX21pbl9kb3NlX3N0ZCwgbmEucm0gPSBUKSwNCiAgICAgICAgICAgICAgICAgc2RfbWluID0gc2QoY29tcG91bmRfbWluX2Rvc2Vfc3RkLCBuYS5ybSA9IFQpLA0KICAgICAgICAgICAgICAgICBtaW5fbWluID0gIG1pbihjb21wb3VuZF9taW5fZG9zZV9zdGQsIG5hLnJtID0gVCksDQogICAgICAgICAgICAgICAgIG1heF9taW4gPSAgbWF4KGNvbXBvdW5kX21pbl9kb3NlX3N0ZCwgbmEucm0gPSBUKSwNCiAgICAgICAgICAgICAgICAgbWVkaWFuX21heCA9ICBtZWRpYW4oY29tcG91bmRfbWF4X2Rvc2Vfc3RkLCBuYS5ybSA9IFQpLA0KICAgICAgICAgICAgICAgICBzZF9tYXggPSBzZChjb21wb3VuZF9tYXhfZG9zZV9zdGQsIG5hLnJtID0gVCksDQogICAgICAgICAgICAgICAgIG1pbl9tYXggPSAgbWluKGNvbXBvdW5kX21heF9kb3NlX3N0ZCwgbmEucm0gPSBUKSwNCiAgICAgICAgICAgICAgICAgbWF4X21heCA9ICBtYXgoY29tcG91bmRfbWF4X2Rvc2Vfc3RkLCBuYS5ybSA9IFQpLA0KICAgICAgICAgICAgICAgICBtZWRpYW5fcmFuZ2UgPSAgbWVkaWFuKHJhbmdlLCBuYS5ybSA9IFQpLA0KICAgICAgICAgICAgICAgICBzZF9yYW5nZSA9IHNkKHJhbmdlLCBuYS5ybSA9IFQpLA0KICAgICAgICAgICAgICAgICBtaW5fcmFuZ2UgPSAgbWluKHJhbmdlLCBuYS5ybSA9IFQpLA0KICAgICAgICAgICAgICAgICBtYXhfcmFuZ2UgPSAgbWF4KHJhbmdlLCBuYS5ybSA9IFQpKQ0KYGBgDQoNCkEgcGxvdCBmb3IgbWluaW11bSBkb3NlcywgaXRzIG9uIHRoZSBsb2cgYXhpcyBiZWNhdXNlIHRoZSBkaXN0cmlidXRpb24gaXMgaGlnaGx5IHNrZXdlZA0KbW90aXZhdGlvbl9jb2xvdXJfdGhlbWUNCg0KYGBge3J9DQptb3RpdmF0aW9uX2NvbG91cl90aGVtZSA8LSBjKCIjNjBCRDZDIiwgIiNEMzU5QTEiLCAiIzNDODJDNCIpDQoNCm1pbl9jb25jX2ZpZyA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKGNvbXBvdW5kX21pbl9kb3NlX3VuaXRfc3RkID09ICJ1Zy9MIikgJT4lIA0KICBnZ3Bsb3QoYWVzKHg9bG9nKGNvbXBvdW5kX21pbl9kb3NlX3N0ZCksIGZpbGwgPSBzdHVkeV9tb3RpdmF0aW9uLCBjb2xvdXIgPSBzdHVkeV9tb3RpdmF0aW9uKSkgKw0KICBzdGF0X3NsYWIoYWxwaGEgPSAwLjYsIGxpbmV3aWR0aCA9IDEuNSwgY29sb3VyID0gTkEpICsNCiAgc3RhdF9wb2ludGludGVydmFsKHBvaW50X2ludGVydmFsID0gIm1lZGlhbl9xaSIsDQogICAgICAgICAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gLjQsIHByZXNlcnZlID0gInNpbmdsZSIpLA0KICAgICAgICAgICAgICAgICAgICAgLndpZHRoID0gYygwLjg5LCAwLjk1KSkgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBtb3RpdmF0aW9uX2NvbG91cl90aGVtZSwgbmFtZSA9ICJTdHVkeSBtb3RpdmF0aW9uIiwgZ3VpZGUgPSAnbm9uZScpICsNCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBtb3RpdmF0aW9uX2NvbG91cl90aGVtZSwgbmFtZSA9ICJTdHVkeSBtb3RpdmF0aW9uIikgKw0KICB0aGVtZV9jbGFzc2ljKCkgKw0KICBsYWJzKA0KICAgIHggPSAiTG9nMTAgbWluaW11bSBkb3NlICh1Zy9MKSIsDQogICAgeSA9ICJEZW5zaXR5Ig0KICApICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJib3R0b20iKQ0KDQptaW5fY29uY19maWcNCmBgYA0KDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQ0Kc2V0d2QoZmlndXJlc19wYXRoKQ0KZ2dzYXZlKCJjb21wX21pbl9jb25jX2ZpZy5wZGYiLCBwbG90ID0gbWluX2NvbmNfZmlnLCB3aWR0aCA9IDUsIGhlaWdodCA9IDYpDQpgYGANCg0KQSBzdW1tYXJ5IHRhYmxlIHNvIHdlIGNhbiBzZWUgd2hhdCB0aGUgY29ycmVzcG9uZGluZyByYXcgdmFsdWVzIGFyZSBpbiB0aGUgcGxvdA0KDQpgYGB7cn0NCm1pbl9jb25jX3N1bW1hcnkgPC0gRUlQQUFCX2RhdGFiYXNlICU+JQ0KICBkcGx5cjo6ZmlsdGVyKGNvbXBvdW5kX21pbl9kb3NlX3VuaXRfc3RkID09ICJ1Zy9MIikgJT4lDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIGRwbHlyOjpzdW1tYXJpc2UoDQogICAgbWVkaWFuID0gbWVkaWFuKGxvZyhjb21wb3VuZF9taW5fZG9zZV9zdGQpLCBuYS5ybSA9IFRSVUUpLA0KICAgIGxvd2VyXzg5ID0gcXVhbnRpbGUobG9nKGNvbXBvdW5kX21pbl9kb3NlX3N0ZCksIHByb2JzID0gMC4xMSwgbmEucm0gPSBUUlVFKSwNCiAgICB1cHBlcl84OSA9IHF1YW50aWxlKGxvZyhjb21wb3VuZF9taW5fZG9zZV9zdGQpLCBwcm9icyA9IDAuODksIG5hLnJtID0gVFJVRSksDQogICAgbG93ZXJfOTUgPSBxdWFudGlsZShsb2coY29tcG91bmRfbWluX2Rvc2Vfc3RkKSwgcHJvYnMgPSAwLjA1LCBuYS5ybSA9IFRSVUUpLA0KICAgIHVwcGVyXzk1ID0gcXVhbnRpbGUobG9nKGNvbXBvdW5kX21pbl9kb3NlX3N0ZCksIHByb2JzID0gMC45NSwgbmEucm0gPSBUUlVFKSwNCiAgICAuZ3JvdXBzID0gImRyb3AiDQogICkgJT4lDQogICMgVHJhbnNmb3JtIHRvIGEgZm9ybWF0IHN1aXRhYmxlIGZvciBnZ3Bsb3QgYW5ub3RhdGlvbg0KICBwaXZvdF9sb25nZXIoY29scyA9IC1zdHVkeV9tb3RpdmF0aW9uLCBuYW1lc190byA9ICJzdGF0IiwgdmFsdWVzX3RvID0gInZhbHVlIikgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHZhdWxlX3JhdyA9IGZvcm1hdChleHAodmFsdWUpLCBzY2llbnRpZmljID0gRkFMU0UpKQ0KbWluX2NvbmNfc3VtbWFyeQ0KYGBgDQoNCkEgcGxvdCBmb3IgbWF4aW11bSBkb3NlcywgaXRzIG9uIHRoZSBsb2cgYXhpcyBiZWNhdXNlIHRoZSBkaXN0cmlidXRpb24gaXMgaGlnaGx5IHNrZXdlZA0KbW90aXZhdGlvbl9jb2xvdXJfdGhlbWUNCg0KYGBge3J9DQptb3RpdmF0aW9uX2NvbG91cl90aGVtZSA8LSBjKCIjNjBCRDZDIiwgIiNEMzU5QTEiLCAiIzNDODJDNCIpDQoNCm1heF9jb25jX2ZpZyA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKGNvbXBvdW5kX21pbl9kb3NlX3VuaXRfc3RkID09ICJ1Zy9MIikgJT4lIA0KICBnZ3Bsb3QoYWVzKHg9bG9nKGNvbXBvdW5kX21heF9kb3NlX3N0ZCksIGZpbGwgPSBzdHVkeV9tb3RpdmF0aW9uLCBjb2xvdXIgPSBzdHVkeV9tb3RpdmF0aW9uKSkgKw0KICBzdGF0X3NsYWIoYWxwaGEgPSAwLjYsIGxpbmV3aWR0aCA9IDEuNSwgY29sb3VyID0gTkEpICsNCiAgc3RhdF9wb2ludGludGVydmFsKHBvaW50X2ludGVydmFsID0gIm1lZGlhbl9xaSIsDQogICAgICAgICAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gLjQsIHByZXNlcnZlID0gInNpbmdsZSIpLA0KICAgICAgICAgICAgICAgICAgICAgLndpZHRoID0gYygwLjg5LCAwLjk1KSkgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBtb3RpdmF0aW9uX2NvbG91cl90aGVtZSwgbmFtZSA9ICJTdHVkeSBtb3RpdmF0aW9uIiwgZ3VpZGUgPSAnbm9uZScpICsNCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBtb3RpdmF0aW9uX2NvbG91cl90aGVtZSwgbmFtZSA9ICJTdHVkeSBtb3RpdmF0aW9uIikgKw0KICB0aGVtZV9jbGFzc2ljKCkgKw0KICBsYWJzKA0KICAgIHggPSAiTG9nMTAgbWF4aW11bSBkb3NlICh1Zy9MKSIsDQogICAgeSA9ICJEZW5zaXR5Ig0KICApICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJib3R0b20iKQ0KDQptYXhfY29uY19maWcNCmBgYA0KDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQ0Kc2V0d2QoZmlndXJlc19wYXRoKQ0KZ2dzYXZlKCJjb21wX21heF9jb25jX2ZpZy5wZGYiLCBwbG90ID0gbWF4X2NvbmNfZmlnLCB3aWR0aCA9IDUsIGhlaWdodCA9IDYpDQpgYGANCg0KQSBzdW1tYXJ5IHRhYmxlIHNvIHdlIGNhbiBzZWUgd2hhdCB0aGUgY29ycmVzcG9uZGluZyByYXcgdmFsdWVzIGFyZSBpbiB0aGUgcGxvdA0KDQpgYGB7cn0NCm1heF9jb25jX3N1bW1hcnkgPC0gRUlQQUFCX2RhdGFiYXNlICU+JQ0KICBkcGx5cjo6ZmlsdGVyKGNvbXBvdW5kX21pbl9kb3NlX3VuaXRfc3RkID09ICJ1Zy9MIikgJT4lDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIGRwbHlyOjpzdW1tYXJpc2UoDQogICAgbWVkaWFuID0gbWVkaWFuKGxvZyhjb21wb3VuZF9tYXhfZG9zZV9zdGQpLCBuYS5ybSA9IFRSVUUpLA0KICAgIGxvd2VyXzg5ID0gcXVhbnRpbGUobG9nKGNvbXBvdW5kX21heF9kb3NlX3N0ZCksIHByb2JzID0gMC4xMSwgbmEucm0gPSBUUlVFKSwNCiAgICB1cHBlcl84OSA9IHF1YW50aWxlKGxvZyhjb21wb3VuZF9tYXhfZG9zZV9zdGQpLCBwcm9icyA9IDAuODksIG5hLnJtID0gVFJVRSksDQogICAgbG93ZXJfOTUgPSBxdWFudGlsZShsb2coY29tcG91bmRfbWF4X2Rvc2Vfc3RkKSwgcHJvYnMgPSAwLjA1LCBuYS5ybSA9IFRSVUUpLA0KICAgIHVwcGVyXzk1ID0gcXVhbnRpbGUobG9nKGNvbXBvdW5kX21heF9kb3NlX3N0ZCksIHByb2JzID0gMC45NSwgbmEucm0gPSBUUlVFKSwNCiAgICAuZ3JvdXBzID0gImRyb3AiDQogICkgJT4lDQogICMgVHJhbnNmb3JtIHRvIGEgZm9ybWF0IHN1aXRhYmxlIGZvciBnZ3Bsb3QgYW5ub3RhdGlvbg0KICBwaXZvdF9sb25nZXIoY29scyA9IC1zdHVkeV9tb3RpdmF0aW9uLCBuYW1lc190byA9ICJzdGF0IiwgdmFsdWVzX3RvID0gInZhbHVlIikgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHZhdWxlX3JhdyA9IGZvcm1hdChleHAodmFsdWUpLCBzY2llbnRpZmljID0gRkFMU0UpKQ0KbWF4X2NvbmNfc3VtbWFyeQ0KYGBgDQoNCkEgcGxvdCBmb3IgdGhlIHJhbmdlIG9mIGRvc2VzLCBpdHMgb24gdGhlIGxvZyBheGlzIGJlY2F1c2UgdGhlIGRpc3RyaWJ1dGlvbiBpcyBoaWdobHkgc2tld2VkLiBUaGlzIGluY2x1ZGVzIG9ubHkgc3R1ZGllcyB0aGF0IGhhZCBtb3JlIHRoZW4gb25lIGRvc2UgYW5kIHJlcG9ydGVkIGNvbmNlbnRyYXRpb24gaW4gYSBtYXNzIHRvIHZvbHVtZSBtZXRyaWMuIA0KDQpgYGB7cn0NCm1vdGl2YXRpb25fY29sb3VyX3RoZW1lIDwtIGMoIiM2MEJENkMiLCAiI0QzNTlBMSIsICIjM0M4MkM0IikNCg0KcmFuZ2VfY29uY19maWcgPC0gRUlQQUFCX2RhdGFiYXNlICU+JSANCiAgZHBseXI6OmZpbHRlcihjb21wb3VuZF9taW5fZG9zZV91bml0X3N0ZCA9PSAidWcvTCIpICU+JSANCiAgZHBseXI6OmZpbHRlcihyYW5nZSA+IDApICU+JSANCiAgZ2dwbG90KGFlcyh4PWxvZyhyYW5nZSksIGZpbGwgPSBzdHVkeV9tb3RpdmF0aW9uLCBjb2xvdXIgPSBzdHVkeV9tb3RpdmF0aW9uKSkgKw0KICBzdGF0X3NsYWIoYWxwaGEgPSAwLjYsIGxpbmV3aWR0aCA9IDEuNSwgY29sb3VyID0gTkEpICsNCiAgc3RhdF9wb2ludGludGVydmFsKHBvaW50X2ludGVydmFsID0gIm1lZGlhbl9xaSIsDQogICAgICAgICAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gLjQsIHByZXNlcnZlID0gInNpbmdsZSIpLA0KICAgICAgICAgICAgICAgICAgICAgLndpZHRoID0gYygwLjg5LCAwLjk1KSkgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBtb3RpdmF0aW9uX2NvbG91cl90aGVtZSwgbmFtZSA9ICJTdHVkeSBtb3RpdmF0aW9uIiwgZ3VpZGUgPSAnbm9uZScpICsNCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBtb3RpdmF0aW9uX2NvbG91cl90aGVtZSwgbmFtZSA9ICJTdHVkeSBtb3RpdmF0aW9uIikgKw0KICB0aGVtZV9jbGFzc2ljKCkgKw0KICBsYWJzKA0KICAgIHggPSAiTG9nMTAgcmFuZ2UgKHVnL0wpIiwNCiAgICB5ID0gIkRlbnNpdHkiDQogICkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb249ImJvdHRvbSIpDQoNCnJhbmdlX2NvbmNfZmlnDQpgYGANCg0KDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCnNldHdkKGZpZ3VyZXNfcGF0aCkNCmdnc2F2ZSgiY29tcF9yYW5nZV9jb25jX2ZpZy5wZGYiLCBwbG90ID0gcmFuZ2VfY29uY19maWcsIHdpZHRoID0gNSwgaGVpZ2h0ID0gNikNCmBgYA0KDQoNCkEgc3VtbWFyeSB0YWJsZSBzbyB3ZSBjYW4gc2VlIHdoYXQgdGhlIGNvcnJlc3BvbmRpbmcgcmF3IHZhbHVlcyBhcmUgaW4gdGhlIHBsb3QNCg0KYGBge3J9DQpyYW5nZV9jb25jX3N1bW1hcnkgPC0gRUlQQUFCX2RhdGFiYXNlICU+JQ0KICBkcGx5cjo6ZmlsdGVyKGNvbXBvdW5kX21pbl9kb3NlX3VuaXRfc3RkID09ICJ1Zy9MIiwNCiAgICAgICAgICAgICAgICByYW5nZSA+IDApICU+JQ0KICBkcGx5cjo6Z3JvdXBfYnkoc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBzdW1tYXJpc2UoDQogICAgbWVkaWFuID0gbWVkaWFuKGxvZyhyYW5nZSksIG5hLnJtID0gVFJVRSksDQogICAgbG93ZXJfODkgPSBxdWFudGlsZShsb2cocmFuZ2UpLCBwcm9icyA9IDAuMDU1LCBuYS5ybSA9IFRSVUUpLA0KICAgIHVwcGVyXzg5ID0gcXVhbnRpbGUobG9nKHJhbmdlKSwgcHJvYnMgPSAwLjk0NSwgbmEucm0gPSBUUlVFKSwNCiAgICBsb3dlcl85NSA9IHF1YW50aWxlKGxvZyhyYW5nZSksIHByb2JzID0gMC4wMjUsIG5hLnJtID0gVFJVRSksDQogICAgdXBwZXJfOTUgPSBxdWFudGlsZShsb2cocmFuZ2UpLCBwcm9icyA9IDAuOTc1LCBuYS5ybSA9IFRSVUUpDQogICkgJT4lDQogICMgVHJhbnNmb3JtIHRvIGEgZm9ybWF0IHN1aXRhYmxlIGZvciBnZ3Bsb3QgYW5ub3RhdGlvbg0KICBwaXZvdF9sb25nZXIoY29scyA9IC1zdHVkeV9tb3RpdmF0aW9uLCBuYW1lc190byA9ICJzdGF0IiwgdmFsdWVzX3RvID0gInZhbHVlIikgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHZhdWxlX3JhdyA9IGZvcm1hdChleHAodmFsdWUpLCBzY2llbnRpZmljID0gRkFMU0UpKQ0KcmFuZ2VfY29uY19zdW1tYXJ5DQpgYGANCg0KYGBge3J9DQplbnZfbWluX2NvbmNfZmlnIDwtIEVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIoc3R1ZHlfbW90aXZhdGlvbiA9PSAiRW52aXJvbm1lbnRhbCIpICU+JSANCiAgZHBseXI6OmZpbHRlcihjb21wb3VuZF9taW5fZG9zZV91bml0X3N0ZCA9PSAidWcvTCIpICU+JSANCiAgZ2dwbG90KGFlcyh4PWxvZyhjb21wb3VuZF9taW5fZG9zZV9zdGQpKSkgKw0KICBzdGF0X3NsYWIoYWVzKGFscGhhID0gMC44LCBsaW5ld2lkdGggPSAxLjUpKSArDQogIHN0YXRfcG9pbnRpbnRlcnZhbChwb2ludF9pbnRlcnZhbCA9ICJtZWRpYW5fcWkiLA0KICAgICAgICAgICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IC40LCBwcmVzZXJ2ZSA9ICJzaW5nbGUiKSwNCiAgICAgICAgICAgICAgICAgICAgIC53aWR0aCA9IGMoMC44OSwgMC45NSkpICsNCiAgdGhlbWVfY2xhc3NpYygpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikNCg0KZW52X21pbl9jb25jX2ZpZw0KYGBgDQpBIHN1bW1hcnkgdGFibGUgc28gd2UgY2FuIHNlZSB3aGF0IHRoZSBjb3JyZXNwb25kaW5nIHJhdyB2YWx1ZXMgYXJlIGluIHRoZSBwbG90DQoNCmBgYHtyfQ0KZW52X2NvbmNfc3VtbWFyeSA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lDQogIGZpbHRlcihzdHVkeV9tb3RpdmF0aW9uID09ICJFbnZpcm9ubWVudGFsIiwgDQogICAgICAgICBjb21wb3VuZF9taW5fZG9zZV91bml0X3N0ZCA9PSAidWcvTCIpICU+JQ0KICBzdW1tYXJpc2UoDQogICAgbWVkaWFuID0gbWVkaWFuKGxvZyhjb21wb3VuZF9taW5fZG9zZV9zdGQpLCBuYS5ybSA9IFRSVUUpLA0KICAgIGxvd2VyXzg5ID0gcXVhbnRpbGUobG9nKGNvbXBvdW5kX21pbl9kb3NlX3N0ZCksIHByb2JzID0gMC4wNTUsIG5hLnJtID0gVFJVRSksDQogICAgdXBwZXJfODkgPSBxdWFudGlsZShsb2coY29tcG91bmRfbWluX2Rvc2Vfc3RkKSwgcHJvYnMgPSAwLjk0NSwgbmEucm0gPSBUUlVFKSwNCiAgICBsb3dlcl85NSA9IHF1YW50aWxlKGxvZyhjb21wb3VuZF9taW5fZG9zZV9zdGQpLCBwcm9icyA9IDAuMDI1LCBuYS5ybSA9IFRSVUUpLA0KICAgIHVwcGVyXzk1ID0gcXVhbnRpbGUobG9nKGNvbXBvdW5kX21pbl9kb3NlX3N0ZCksIHByb2JzID0gMC45NzUsIG5hLnJtID0gVFJVRSkNCiAgKSAlPiUNCiAgIyBUcmFuc2Zvcm0gdG8gYSBmb3JtYXQgc3VpdGFibGUgZm9yIGdncGxvdCBhbm5vdGF0aW9uDQogIHBpdm90X2xvbmdlcihjb2xzID0gZXZlcnl0aGluZygpLCBuYW1lc190byA9ICJzdGF0IiwgdmFsdWVzX3RvID0gInZhbHVlIikgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHZhdWxlX3JhdyA9IGZvcm1hdChleHAodmFsdWUpLCBzY2llbnRpZmljID0gRkFMU0UpKQ0KZW52X2NvbmNfc3VtbWFyeQ0KYGBgDQoNCiMjIDEzLjkgRXhwb3N1cmUgbG9jYXRpb24NCg0KV2hlcmUgdGhlIGV4cG9zdXJlIGl0c2VsZiB3YXMgY29uZHVjdGVkDQoNCmBgYHtyfQ0KRUlQQUFCX2RhdGFiYXNlICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KGNvbXBvdW5kX2V4cG9zdXJlX2xvY2F0aW9uKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBuKCkpICU+JSANCiAgZHBseXI6Om11dGF0ZSh0b3RhbCA9IHN1bShuKSwNCiAgICAgICAgICAgICAgICBwZXJlY2VudCA9IHJvdW5kKG4vdG90YWwqMTAwLDEpKQ0KYGBgDQoNCiMgMTQgQmVoYXZpb3VyDQoNCiMjIDE0LjEgQ291bnRzIG9mIGNhdGFnb2lyZXMNCg0KRmlyc3QgSSB3aWxsIG1ha2UgYSBuZXcgdmFyaWFibGUgY2FsbGVkIGJlYWh2X2NhdGdvcnlfbiwgd2hpY2ggd2lsbCBsb29rIGF0IGhvdyBtYW55IG9mIG91ciAxMCBicm9hZCBiZWhhdmlvdXJhbCBjYXRlZ29yaWVzIHdlcmUgbWVhc3VyZWQgaW4gdGhlIGFydGljbGUuIA0KDQpUaGUgMTAgb3Zlci1hcmNoaW5nIGNhdGVnb3JpZXMgd2VyZTogKDEpIG1vdmVtZW50IGFuZCBsb2NvbW90aW9uLCAoMikgcHJlLW1hdGluZyBhbmQgbWF0aW5nIGJlaGF2aW91ciwgKDMpIHBvc3QtbWF0aW5nIGJlaGF2aW91ciwgKDQpIGFnZ3Jlc3Npb24sICg1KSBzb2NpYWxpdHksICg2KSBjb2duaXRpb24gYW5kIGxlYXJuaW5nLCAoNykgYW54aWV0eSBhbmQgYm9sZG5lc3MsICg4KSBmb3JhZ2luZyBhbmQgZmVlZGluZywgKDkpIGFudGlwcmVkYXRvciBiZWhhdmlvdXIsIGFuZCAoMTApIG90aGVyIGJlaGF2aW91cnMgbm90IGNhdGVnb3Jpc2VkDQoNClRoaXMgd2lsbCB0YWtlIHRoZSBzb21lIG9mIGFsbCB0aGUgYmVoYXZpb3VyIGNhdGVnb3JpZXMuLCBzbyBjYW4gcmFuZ2UgZnJvbSAxIHRvIDEwIGZvciBhIHNpbmdsZSBiZWhhdmlvdXJhbCBjYXRlZ29yeSB0byBhbGwgY2F0ZWdvcmllcy4NCg0KYGBge3J9DQpFSVBBQUJfZGF0YWJhc2UgPC0gRUlQQUFCX2RhdGFiYXNlICU+JQ0KICBkcGx5cjo6bXV0YXRlKGJlaGF2X2NhdGVnb3J5X24gPSByb3dTdW1zKGFjcm9zcyhzdGFydHNfd2l0aCgiYmVoYXZfIikgJiBlbmRzX3dpdGgoIl9ib29sZWFuIikpKSkNCmBgYA0KDQoNClRoZSBtYWpvcml0eSBvZiBldmlkZW5jZSBzZWVtcyB0byBiZSBiYXNlZCBvbiBhIHNpbmdsZSBiZWhhdmlvdXJhbCBjYXRlZ29yeQ0KDQpgYGB7cn0NCkVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShiZWhhdl9jYXRlZ29yeV9uKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBuKCkpICU+JSANCiAgZHBseXI6Om11dGF0ZShwZXJjZW50ID0gcm91bmQobi9zdW0obikqMTAwLDEpKQ0KYGBgDQpJcyB0aGlzIHRoZSBzYW1lIGJ5IHN0dWR5IG1vdGl2YXRpb24gDQoNCmBgYHtyfQ0KRUlQQUFCX2RhdGFiYXNlICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KGJlaGF2X2NhdGVnb3J5X24sIHN0dWR5X21vdGl2YXRpb24pICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IG4oKSkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHRvdGFsX21vdGl2YXRpb24gPSBzdW0obikpICU+JSANCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjptdXRhdGUocGVyY2VudCA9IHJvdW5kKG4vdG90YWxfbW90aXZhdGlvbioxMDAsMSkpDQpgYGANCg0KDQoNCkhlcmUgSSBtYWtlIGEgZGF0YWZyYW1lIHdoZXJlIEkgaGF2ZSBwaXZvdGVkIHRoZSBkYXRhIHRvIGxvbmcgZm9ybWF0ZSBiYXNlZCBvbiBlYWNoIG9mIHRoZSAxMCBiZWhhdmlvdXIgY2F0ZWdvcmllcy4gVGhpcyBkYXRhZnJhbWUgY2FuIGJlIHVzZWQgdG8gYXNrIG1vcmUgc3BlZmljIHF1ZXN0aW9zbiBhYm91dCB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gc3BlY2llcywgY29tcG91bmQsIGFuZCBiZWhhdmlvdXIuIA0KDQpCdXQgZmlyc3QgbGV0J3MgdXNlIGl0IHRvIHNlZSB3aGF0IGJlaGF2aW91cnMgYXJlIG1vc3QgY29tbW9uIG92ZXJhbGwgYWxsLCBhbmQgd2l0aGluIGVhY2ggc3R1ZHkgbW90aXZhdGlvbi4gDQogIA0KYGBge3J9DQpiaW5hcnlfYmVoYXYgPC0gRUlQQUFCX2RhdGFiYXNlICU+JSANCiAgZHBseXI6OnNlbGVjdCgoc3RhcnRzX3dpdGgoImJlaGF2XyIpICYgZW5kc193aXRoKCJfYm9vbGVhbiIpKSkgJT4lIA0KICBjb2xuYW1lcygpDQoNClBJQ09fbG9uZyA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lIA0KICB0aWR5cjo6cGl2b3RfbG9uZ2VyKC4sIA0KICAgICAgICAgICAgICAgICAgICAgIGNvbHMgPSBhbGxfb2YoYmluYXJ5X2JlaGF2KSwNCiAgICAgICAgICAgICAgICAgICAgICBuYW1lc190byA9ICJiZWhhdl9jYXRlZ29yeSIsIA0KICAgICAgICAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJ2YWx1ZSIpICU+JSANCiAgZHBseXI6OnNlbGVjdChhcnRpY2xlX2lkLCBzdHVkeV9tb3RpdmF0aW9uLCBzcGVjaWVzX25hbWUsIHNwZWNpZXNfY2xhc3MsIA0KICAgICAgICAgICAgICAgIGNvbXBvdW5kX25hbWUsIGNvbXBvdW5kX2F0Y19sZXZlbF8zLCBiZWhhdl9jYXRlZ29yeSwgdmFsdWUpICU+JSANCiAgZHBseXI6Om11dGF0ZShiZWhhdl9jYXRlZ29yeSA9IGJlaGF2X2NhdGVnb3J5ICU+JSBzdHJfcmVtb3ZlKCJiZWhhdl8iKSAlPiUgc3RyX3JlbW92ZSgiX2Jvb2xlYW4iKSkNClBJQ09fbG9uZw0KYGBgDQoNCg0KYGBge3J9DQpiZWhhdl9vdmVyYWxsIDwtIFBJQ09fbG9uZyAlPiUgDQogIGRwbHlyOjpncm91cF9ieShiZWhhdl9jYXRlZ29yeSkgJT4lIA0KICByZWZyYW1lKG4gPSBzdW0odmFsdWUpKSAlPiUgDQogIGRwbHlyOjptdXRhdGUocGVyY2VudCA9IHJvdW5kKG4vc3VtKG4pKjEwMCwgMSkpICU+JSANCiAgZHBseXI6OmFycmFuZ2UoZGVzYyhuKSkNCmJlaGF2X292ZXJhbGwNCmBgYA0KDQpgYGB7cn0NCmJlaGF2X21vdGl2YXRpb24gPC0gUElDT19sb25nICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KGJlaGF2X2NhdGVnb3J5LCBzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIGRwbHlyOjpzdW1tYXJpc2UobiA9IHN1bSh2YWx1ZSksIC5ncm91cHMgPSAnZHJvcCcpICU+JQ0KICB0aWR5cjo6Y29tcGxldGUoYmVoYXZfY2F0ZWdvcnksIHN0dWR5X21vdGl2YXRpb24sIGZpbGwgPSBsaXN0KG4gPSAwKSkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHRvdGFsX21vdGl2YXRpb24gPSBzdW0obikpICU+JSANCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjptdXRhdGUocGVyY2VudCA9IHJvdW5kKG4vdG90YWxfbW90aXZhdGlvbioxMDAsMSkpICU+JSANCiAgZHBseXI6OnNlbGVjdCgtdG90YWxfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6YXJyYW5nZShkZXNjKHN0dWR5X21vdGl2YXRpb24pKQ0KDQpiZWhhdl9vdmVyYWxsIDwtIGJlaGF2X21vdGl2YXRpb24gJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoYmVoYXZfY2F0ZWdvcnkpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IHN1bShuKSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHBlcmNlbnQgPSByb3VuZChuL3N1bShuKSoxMDAsMSksDQogICAgICAgICAgICAgICAgc3R1ZHlfbW90aXZhdGlvbiA9ICJPdmVyYWxsIikNCg0KYmVoYXZfbW90aXZhdGlvbiA8LSByYmluZChiZWhhdl9vdmVyYWxsLCBiZWhhdl9tb3RpdmF0aW9uKQ0KYmVoYXZfbW90aXZhdGlvbg0KYGBgDQoNCg0KYGBge3J9DQptb3RpdmF0aW9uX2NvbG91cl90aGVtZSA8LSBjKCJncmV5IiwgIiM2MEJENkMiLCAiI0QzNTlBMSIsICIjM0M4MkM0IikNCmJlaGF2X29yZGVyIDwtIGMoIm1vdmVtZW50IiwgImJvbGRuZXNzIiwgImZvcmFnaW5nIiwgImFudGlwcmVkYXRvciIsICJtYXRpbmciLCAicG9zdF9tYXRpbmciLCAiYWdyZXNzaW9uIiwgInNvY2lhbGl0eSIsICJjb2duaXRpb24iLCAibm9uY2F0IikNCnN0dWR5X21vdGl2YXRpb25fb3JkZXIgPC0gYygiT3ZlcmFsbCIsICJFbnZpcm9ubWVudGFsIiwgIk1lZGljYWwiLCAiQmFzaWMgcmVzZWFyY2giKQ0KDQoNCmJlaGF2X21vdGl2YXRpb25fZmlnIDwtIGJlaGF2X21vdGl2YXRpb24gJT4lIA0KICBkcGx5cjo6bXV0YXRlKGJlaGF2X2NhdGVnb3J5ID0gZmFjdG9yKGJlaGF2X2NhdGVnb3J5LCBsZXZlbHMgPSByZXYoYmVoYXZfb3JkZXIpKSwNCiAgICAgICAgICAgICAgICBzdHVkeV9tb3RpdmF0aW9uID0gZmFjdG9yKHN0dWR5X21vdGl2YXRpb24sIGxldmVscyA9IHN0dWR5X21vdGl2YXRpb25fb3JkZXIpKSAlPiUgDQogIGdncGxvdChhZXMoeD1iZWhhdl9jYXRlZ29yeSwgeT1wZXJjZW50LCBjb2xvdXIgPSBzdHVkeV9tb3RpdmF0aW9uLCANCiAgICAgICAgICAgICBmaWxsID0gc3R1ZHlfbW90aXZhdGlvbiksIGdyb3VwID0gc3R1ZHlfbW90aXZhdGlvbikgKw0KICBnZW9tX2NvbCh3aWR0aCA9IDAuMSwgY29sb3VyID0gTkEpICsNCiAgZ2VvbV9wb2ludChzaXplID0gMykgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGVyY2VudCksIHZqdXN0ID0gLTAuMywgc2l6ZT0zLjUsIGNvbG9yPSJibGFjayIpICsNCiAgdGhlbWVfY2xhc3NpYygpICsNCiAgZmFjZXRfZ3JpZChjb2xzID0gdmFycyhzdHVkeV9tb3RpdmF0aW9uKSkgKw0KICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IG1vdGl2YXRpb25fY29sb3VyX3RoZW1lLCBuYW1lID0gIlN0dWR5IG1vdGl2YXRpb24iKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IG1vdGl2YXRpb25fY29sb3VyX3RoZW1lLCBuYW1lID0gIlN0dWR5IG1vdGl2YXRpb24iKSArDQogIGNvb3JkX2ZsaXAoKSArDQogIGxhYnMoDQogICAgeCA9ICIiLA0KICAgIHkgPSAiUGVyY2VudGFnZSINCiAgKSArDQogIHRoZW1lKA0KICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMSkNCiAgICkNCg0KYmVoYXZfbW90aXZhdGlvbl9maWcNCmBgYA0KDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQ0Kc2V0d2QoZmlndXJlc19wYXRoKQ0KZ2dzYXZlKCJiZWhhdl9tb3RpdmF0aW9uX2ZpZy5wZGYiLCBwbG90ID0gYmVoYXZfbW90aXZhdGlvbl9maWcsIHdpZHRoID0gMTAsIGhlaWdodCA9IDUpDQpgYGANCg0KIyMgMTQuMiBCZWhhdmlvdXIgc3ViLWNhdGVnb3JpZXMNCg0KYGBge3J9DQpiZWhhdl9zZWxlY3QgPC0gRUlQQUFCX2RhdGFiYXNlICU+JSANCiAgZHBseXI6OnNlbGVjdCgoc3RhcnRzX3dpdGgoImJlaGF2XyIpICYgIWVuZHNfd2l0aCgiX2Jvb2xlYW4iKSAmICFlbmRzX3dpdGgoImlzX3NvY2lhbF9jb250ZXh0IikgJiAhZW5kc193aXRoKCJ0ZXN0X2xvY2F0aW9uIikgJiAhZW5kc193aXRoKCJjYXRlZ29yeV9uIikpKSAlPiUgDQogIGNvbG5hbWVzKCkNCg0KDQpiZWhhdl9zdWJfY2F0X2xvbmcgPC0gRUlQQUFCX2RhdGFiYXNlICU+JSANCiAgdGlkeXI6OnBpdm90X2xvbmdlciguLCANCiAgICAgICAgICAgICAgICAgICAgICBjb2xzID0gYWxsX29mKGJlaGF2X3NlbGVjdCksDQogICAgICAgICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAicGFyZW50X2NhdGVnb3J5IiwgDQogICAgICAgICAgICAgICAgICAgICAgdmFsdWVzX3RvID0gInN1Yl9jYXRlZ29yeSIpICU+JSANCiAgZHBseXI6OnNlbGVjdChhcnRpY2xlX2lkLCBzdHVkeV9tb3RpdmF0aW9uLCBzcGVjaWVzX25hbWUsIHNwZWNpZXNfY2xhc3MsIA0KICAgICAgICAgICAgICAgIGNvbXBvdW5kX25hbWUsIGNvbXBvdW5kX2F0Y19sZXZlbF8zLCBwYXJlbnRfY2F0ZWdvcnksIHN1Yl9jYXRlZ29yeSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHBhcmVudF9jYXRlZ29yeSA9IHBhcmVudF9jYXRlZ29yeSAlPiUgc3RyX3JlbW92ZSgiYmVoYXZfIikpICU+JSANCiAgdGlkeXI6OnNlcGFyYXRlX3Jvd3Moc3ViX2NhdGVnb3J5LCBzZXAgPSAiOyIpICU+JSANCiAgZHBseXI6OmZpbHRlcighaXMubmEoc3ViX2NhdGVnb3J5KSkNCmBgYA0KDQoNCmBgYHtyfQ0KYmVoYXZfc3ViX2NhdF9zdW1tYXJ5IDwtIGJlaGF2X3N1Yl9jYXRfbG9uZyAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uLCBwYXJlbnRfY2F0ZWdvcnksIHN1Yl9jYXRlZ29yeSkgJT4lIA0KICBkcGx5cjo6c3VtbWFyaXNlKG5fc3ViX2NhdCA9IG4oKSwgLmdyb3VwcyA9ICdkcm9wJykgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3R1ZHlfbW90aXZhdGlvbiwgcGFyZW50X2NhdGVnb3J5KSAlPiUgDQogIGRwbHlyOjptdXRhdGUobl9wYXJlbnQgPSBzdW0obl9zdWJfY2F0KSkgJT4lIA0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHN0dWR5X21vdGl2YXRpb24pICU+JQ0KICBkcGx5cjo6bXV0YXRlKG5fbW90aXZhdGlvbiA9IHN1bShuX3N1Yl9jYXQpKSAlPiUgDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHBlcmNlbnRfc3ViX2NhdCA9IG5fc3ViX2NhdC9uX3BhcmVudCwNCiAgICAgICAgICAgICAgICBwZXJjZW50X3BhcmVudCA9IG5fcGFyZW50L25fbW90aXZhdGlvbikNCmJlaGF2X3N1Yl9jYXRfc3VtbWFyeQ0KYGBgDQoNCmBgYHtyfQ0KcmluZ19wbG90X3N1YmNhdCA8LSBiZWhhdl9zdWJfY2F0X3N1bW1hcnkgJT4lDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uLCBwYXJlbnRfY2F0ZWdvcnkpICU+JSANCiAgZHBseXI6Om11dGF0ZSh5bWF4ID0gY3Vtc3VtKHBlcmNlbnRfc3ViX2NhdCksDQogICAgICAgICAgICAgICAgeW1pbiA9IGxhZyh5bWF4LDEpLA0KICAgICAgICAgICAgICAgIHltaW4gPSBpZl9lbHNlKGlzLm5hKHltaW4pLCAwLCB5bWluKSwNCiAgICAgICAgICAgICAgICBsYWJlbFBvc2l0aW9uID0gKHltYXgreW1pbikvMiwNCiAgICAgICAgICAgICAgICBsYWJlbCA9IHBhc3RlMChzdWJfY2F0ZWdvcnksICJcbiAobiA9ICIsIG5fc3ViX2NhdCwgIikiKSkgJT4lIA0KICBkcGx5cjo6dW5ncm91cCgpDQpgYGANCg0KIyMjIDE0LjIuMSBNb3ZlbWVudCBwbG90cyANCg0KRmlyc3QgbWFraW5nIGEgY29tcGxldGUgZGF0YXNldCAoYWRkaW5nIHplcm9zIGZvciBtaXNzaW5nIHN1Yi1jYXRlZ29yaWVzLiBpbiBlYWNoIG1vdGl2YXRpb24pLCBhbmQgb3JkZXJpbmcgYnkgb3ZlcmFsbCBwcmV2YWxlbmNlIG9mIHN1Yi1jYXRlZ29yaWVzLg0KDQpgYGB7cn0NCnN1Yl9jYXRlZ29yeV9vcmRlciA8LSBiZWhhdl9zdWJfY2F0X3N1bW1hcnkgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKHBhcmVudF9jYXRlZ29yeSA9PSAibW92ZW1lbnQiKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzdWJfY2F0ZWdvcnkpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IHN1bShuX3N1Yl9jYXQpKSAlPiUgDQogIGRwbHlyOjphcnJhbmdlKG4pICU+JSANCiAgZHBseXI6OnB1bGwoc3ViX2NhdGVnb3J5KQ0KDQptb3ZlbWVudF9zdWJjYXQgPC0gYmVoYXZfc3ViX2NhdF9zdW1tYXJ5ICU+JSANCiAgZHBseXI6OmZpbHRlcihwYXJlbnRfY2F0ZWdvcnkgPT0gIm1vdmVtZW50IikgJT4lIA0KICBkcGx5cjo6c2VsZWN0KHN0dWR5X21vdGl2YXRpb24sIHN1Yl9jYXRlZ29yeSwgcGVyY2VudF9zdWJfY2F0LCBuX3N1Yl9jYXQsIHBlcmNlbnRfcGFyZW50KSAlPiUgDQogIHRpZHlyOjpjb21wbGV0ZShzdWJfY2F0ZWdvcnksIHN0dWR5X21vdGl2YXRpb24sIGZpbGwgPSBsaXN0KHBlcmNlbnRfc3ViX2NhdCA9IDAsIG5fc3ViX2NhdCA9IDApKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoc3ViX2NhdGVnb3J5ID0gZmFjdG9yKHN1Yl9jYXRlZ29yeSwgbGV2ZWxzID0gc3ViX2NhdGVnb3J5X29yZGVyKSkNCmBgYA0KDQoNCmBgYHtyfQ0KYmVoX21vdmVtZW50X3N1YmNhdF9maWcgPC0gbW92ZW1lbnRfc3ViY2F0ICU+JSANCiAgZHBseXI6Om11dGF0ZShwZXJjZW50X3N1Yl9jYXQgPSByb3VuZChwZXJjZW50X3N1Yl9jYXQsMykqMTAwKSAlPiUgDQogIGdncGxvdChhZXMoeD1zdWJfY2F0ZWdvcnksIHk9cGVyY2VudF9zdWJfY2F0LCBjb2xvdXIgPSBzdHVkeV9tb3RpdmF0aW9uLCBmaWxsID0gc3R1ZHlfbW90aXZhdGlvbiwgZ3JvdXAgPSBzdHVkeV9tb3RpdmF0aW9uKSkgKw0KICBnZW9tX2NvbChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC44KSwgd2lkdGggPSAwLjEpICsNCiAgZ2VvbV9wb2ludChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC44KSwgc2l6ZSA9IDMpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHBlcmNlbnRfc3ViX2NhdCksIGhqdXN0PS0wLjYsIHNpemU9My41LCBjb2xvcj0iYmxhY2siLCBwb3NpdGlvbiA9ICBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOCkpICsNCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBtb3RpdmF0aW9uX2NvbG91cl90aGVtZSwgbmFtZSA9ICJTdHVkeSBtb3RpdmF0aW9uIikgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBtb3RpdmF0aW9uX2NvbG91cl90aGVtZSwgbmFtZSA9ICJTdHVkeSBtb3RpdmF0aW9uIikgKw0KICB0aGVtZV9jbGFzc2ljKCkgKw0KICBjb29yZF9mbGlwKCkgKw0KICAgbGFicygNCiAgICB4ID0gIiIsDQogICAgeSA9ICJQZXJjZW50YWdlIG9mIGRhdGEiDQogICkgKw0KICAgdGhlbWUoDQogICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIg0KICAgKQ0KDQpiZWhfbW92ZW1lbnRfc3ViY2F0X2ZpZw0KYGBgDQoNCg0KYGBge3IsIHdhcm5pbmc9RkFMU0V9DQpuX3N1YmNhdCA8LSBtb3ZlbWVudF9zdWJjYXQgJT4lIA0KICBkcGx5cjo6ZGlzdGluY3Qoc3ViX2NhdGVnb3J5KSAlPiUgDQogIG5yb3coLikvMTANCg0Kc2V0d2QoZmlndXJlc19wYXRoKQ0KZ2dzYXZlKCJiZWhfbW92ZW1lbnRfc3ViY2F0X2ZpZy5wZGYiLCBwbG90ID0gYmVoX21vdmVtZW50X3N1YmNhdF9maWcsIHdpZHRoID0gMTAsIGhlaWdodCA9IDExLjcqbl9zdWJjYXQpDQpgYGANCg0KSWYgeW91IHdvdWxkIGxpa2UgdG8gbWFrZSBhIGRvdWdobnV0IGNoYXJ0IGhlcmUncyB0aGUgY29kZS4gSG93ZXZlciwgZm9yIGNhdGVnb3JpZXMgdGhhdCBoYXZlIDUgb3IgbW9yZSBzdWItY2F0ZWdvcmllcyBsaWtlIG1vdmVtZW50IEkgZG9uJ3QgdGhpbmsgdGhpcyBpcyB0aGUgY2xlYXJlc3Qgd2F5IHRvIHByZXNlbnQgdGhlIGRhdGEuDQoNCmBgYHtyfQ0KbW92ZW1lbnRfc3ViY2F0ICU+JSANCiAgZHBseXI6OmFycmFuZ2Uoc3ViX2NhdGVnb3J5KSAlPiUNCiAgZHBseXI6OmFycmFuZ2Uoc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHltYXggPSBjdW1zdW0ocGVyY2VudF9zdWJfY2F0KSwNCiAgICAgICAgICAgICAgICB5bWluID0gbGFnKHltYXgsMSksDQogICAgICAgICAgICAgICAgeW1pbiA9IGlmX2Vsc2UoaXMubmEoeW1pbiksIDAsIHltaW4pLA0KICAgICAgICAgICAgICAgIGxhYmVsUG9zaXRpb24gPSAoeW1heCt5bWluKS8yLA0KICAgICAgICAgICAgICAgIGxhYmVsID0gaWZfZWxzZShuX3N1Yl9jYXQgPT0gMCwgTkEsIG5fc3ViX2NhdCkpICU+JSANCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUNCiAgZ2dwbG90KGFlcyh5bWF4PXltYXgsIHltaW49eW1pbiwgeG1heD00LCB4bWluPTMsIGZpbGw9c3ViX2NhdGVnb3J5KSkgKw0KICBnZW9tX3JlY3QoKSArDQogIGNvb3JkX3BvbGFyKHRoZXRhPSJ5IikgKyANCiAgZ2VvbV9sYWJlbCh4PTQsIGFlcyh5PWxhYmVsUG9zaXRpb24sIGxhYmVsPWxhYmVsKSwgc2l6ZT0zLCBhbHBoYSA9IDAuOCkgKw0KICBmYWNldF93cmFwKH5zdHVkeV9tb3RpdmF0aW9uKSArDQogIHhsaW0oYygyLCA1KSkgKw0KICB0aGVtZV92b2lkKCkgICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpDQpgYGANCg0KIyMjIDE0LjIuMiBCb2xkbmVzcyBwbG90cyANCg0KYGBge3J9DQpzdWJfY2F0ZWdvcnlfb3JkZXIgPC0gYmVoYXZfc3ViX2NhdF9zdW1tYXJ5ICU+JSANCiAgZHBseXI6OmZpbHRlcihwYXJlbnRfY2F0ZWdvcnkgPT0gImJvbGRuZXNzIikgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3ViX2NhdGVnb3J5KSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBzdW0obl9zdWJfY2F0KSkgJT4lIA0KICBkcGx5cjo6YXJyYW5nZShuKSAlPiUgDQogIGRwbHlyOjpwdWxsKHN1Yl9jYXRlZ29yeSkNCg0KYm9sZG5lc3Nfc3ViY2F0IDwtIGJlaGF2X3N1Yl9jYXRfc3VtbWFyeSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIocGFyZW50X2NhdGVnb3J5ID09ICJib2xkbmVzcyIpICU+JSANCiAgZHBseXI6OnNlbGVjdChzdHVkeV9tb3RpdmF0aW9uLCBzdWJfY2F0ZWdvcnksIHBlcmNlbnRfc3ViX2NhdCwgbl9zdWJfY2F0LCBwZXJjZW50X3BhcmVudCkgJT4lIA0KICB0aWR5cjo6Y29tcGxldGUoc3ViX2NhdGVnb3J5LCBzdHVkeV9tb3RpdmF0aW9uLCBmaWxsID0gbGlzdChwZXJjZW50X3N1Yl9jYXQgPSAwLCBuX3N1Yl9jYXQgPSAwKSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHN1Yl9jYXRlZ29yeSA9IGZhY3RvcihzdWJfY2F0ZWdvcnksIGxldmVscyA9IHN1Yl9jYXRlZ29yeV9vcmRlcikpDQpgYGANCg0KDQpgYGB7cn0NCmJlaF9ib2xkbmVzc19zdWJjYXRfZmlnIDwtIGJvbGRuZXNzX3N1YmNhdCAlPiUgDQogIGRwbHlyOjptdXRhdGUocGVyY2VudF9zdWJfY2F0ID0gcm91bmQocGVyY2VudF9zdWJfY2F0LDMpKjEwMCkgJT4lIA0KICBnZ3Bsb3QoYWVzKHg9c3ViX2NhdGVnb3J5LCB5PXBlcmNlbnRfc3ViX2NhdCwgY29sb3VyID0gc3R1ZHlfbW90aXZhdGlvbiwgZmlsbCA9IHN0dWR5X21vdGl2YXRpb24sIGdyb3VwID0gc3R1ZHlfbW90aXZhdGlvbikpICsNCiAgZ2VvbV9jb2wocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOCksIHdpZHRoID0gMC4xKSArDQogIGdlb21fcG9pbnQocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOCksIHNpemUgPSAzKSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBwZXJjZW50X3N1Yl9jYXQpLCBoanVzdD0tMC42LCBzaXplPTMuNSwgY29sb3I9ImJsYWNrIiwgcG9zaXRpb24gPSAgcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjgpKSArDQogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gbW90aXZhdGlvbl9jb2xvdXJfdGhlbWUsIG5hbWUgPSAiU3R1ZHkgbW90aXZhdGlvbiIpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gbW90aXZhdGlvbl9jb2xvdXJfdGhlbWUsIG5hbWUgPSAiU3R1ZHkgbW90aXZhdGlvbiIpICsNCiAgdGhlbWVfY2xhc3NpYygpICsNCiAgY29vcmRfZmxpcCgpICsNCiAgIGxhYnMoDQogICAgeCA9ICIiLA0KICAgIHkgPSAiUGVyY2VudGFnZSBvZiBkYXRhIg0KICApICsNCiAgIHRoZW1lKA0KICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSINCiAgICkNCg0KYmVoX2JvbGRuZXNzX3N1YmNhdF9maWcNCmBgYA0KDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQ0Kbl9zdWJjYXQgPC0gYm9sZG5lc3Nfc3ViY2F0ICU+JSANCiAgZHBseXI6OmRpc3RpbmN0KHN1Yl9jYXRlZ29yeSkgJT4lIA0KICBucm93KC4pLzEwDQoNCnNldHdkKGZpZ3VyZXNfcGF0aCkNCmdnc2F2ZSgiYmVoX2JvbGRuZXNzX3N1YmNhdF9maWcucGRmIiwgcGxvdCA9IGJlaF9ib2xkbmVzc19zdWJjYXRfZmlnLCB3aWR0aCA9IDEwLCBoZWlnaHQgPSAxMS43Km5fc3ViY2F0KQ0KYGBgDQoNCg0KIyMjIDE0LjIuMyBGb3JhZ2luZyBwbG90cyANCg0KYGBge3J9DQpzdWJfY2F0ZWdvcnlfb3JkZXIgPC0gYmVoYXZfc3ViX2NhdF9zdW1tYXJ5ICU+JSANCiAgZHBseXI6OmZpbHRlcihwYXJlbnRfY2F0ZWdvcnkgPT0gImZvcmFnaW5nIikgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3ViX2NhdGVnb3J5KSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBzdW0obl9zdWJfY2F0KSkgJT4lIA0KICBkcGx5cjo6YXJyYW5nZShuKSAlPiUgDQogIGRwbHlyOjpwdWxsKHN1Yl9jYXRlZ29yeSkNCg0KZm9yYWdpbmdfc3ViY2F0IDwtIGJlaGF2X3N1Yl9jYXRfc3VtbWFyeSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIocGFyZW50X2NhdGVnb3J5ID09ICJmb3JhZ2luZyIpICU+JSANCiAgZHBseXI6OnNlbGVjdChzdHVkeV9tb3RpdmF0aW9uLCBzdWJfY2F0ZWdvcnksIHBlcmNlbnRfc3ViX2NhdCwgbl9zdWJfY2F0LCBwZXJjZW50X3BhcmVudCkgJT4lIA0KICB0aWR5cjo6Y29tcGxldGUoc3ViX2NhdGVnb3J5LCBzdHVkeV9tb3RpdmF0aW9uLCBmaWxsID0gbGlzdChwZXJjZW50X3N1Yl9jYXQgPSAwLCBuX3N1Yl9jYXQgPSAwKSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHN1Yl9jYXRlZ29yeSA9IGZhY3RvcihzdWJfY2F0ZWdvcnksIGxldmVscyA9IHN1Yl9jYXRlZ29yeV9vcmRlcikpDQpgYGANCg0KDQpgYGB7cn0NCmJlaF9mb3JhZ2luZ19zdWJjYXRfZmlnIDwtIGZvcmFnaW5nX3N1YmNhdCAlPiUgDQogIGRwbHlyOjptdXRhdGUocGVyY2VudF9zdWJfY2F0ID0gcm91bmQocGVyY2VudF9zdWJfY2F0LDMpKjEwMCkgJT4lIA0KICBnZ3Bsb3QoYWVzKHg9c3ViX2NhdGVnb3J5LCB5PXBlcmNlbnRfc3ViX2NhdCwgY29sb3VyID0gc3R1ZHlfbW90aXZhdGlvbiwgZmlsbCA9IHN0dWR5X21vdGl2YXRpb24sIGdyb3VwID0gc3R1ZHlfbW90aXZhdGlvbikpICsNCiAgZ2VvbV9jb2wocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOCksIHdpZHRoID0gMC4xKSArDQogIGdlb21fcG9pbnQocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOCksIHNpemUgPSAzKSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBwZXJjZW50X3N1Yl9jYXQpLCBoanVzdD0tMC42LCBzaXplPTMuNSwgY29sb3I9ImJsYWNrIiwgcG9zaXRpb24gPSAgcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjgpKSArDQogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gbW90aXZhdGlvbl9jb2xvdXJfdGhlbWUsIG5hbWUgPSAiU3R1ZHkgbW90aXZhdGlvbiIpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gbW90aXZhdGlvbl9jb2xvdXJfdGhlbWUsIG5hbWUgPSAiU3R1ZHkgbW90aXZhdGlvbiIpICsNCiAgdGhlbWVfY2xhc3NpYygpICsNCiAgY29vcmRfZmxpcCgpICsNCiAgIGxhYnMoDQogICAgeCA9ICIiLA0KICAgIHkgPSAiUGVyY2VudGFnZSBvZiBkYXRhIg0KICApICsNCiAgIHRoZW1lKA0KICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSINCiAgICkNCg0KYmVoX2ZvcmFnaW5nX3N1YmNhdF9maWcNCmBgYA0KDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCm5fc3ViY2F0IDwtIGZvcmFnaW5nX3N1YmNhdCAlPiUgDQogIGRwbHlyOjpkaXN0aW5jdChzdWJfY2F0ZWdvcnkpICU+JSANCiAgbnJvdyguKS8xMA0KDQpzZXR3ZChmaWd1cmVzX3BhdGgpDQpnZ3NhdmUoImJlaF9mb3JhZ2luZ19zdWJjYXRfZmlnLnBkZiIsIHBsb3QgPSBiZWhfZm9yYWdpbmdfc3ViY2F0X2ZpZywgd2lkdGggPSAxMCwgaGVpZ2h0ID0gMTEuNypuX3N1YmNhdCkNCmBgYA0KDQoNCiMjIyAxNC4yLjQgQW50aXByZWRhdG9yIHBsb3RzIA0KDQpgYGB7cn0NCnN1Yl9jYXRlZ29yeV9vcmRlciA8LSBiZWhhdl9zdWJfY2F0X3N1bW1hcnkgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKHBhcmVudF9jYXRlZ29yeSA9PSAiYW50aXByZWRhdG9yIikgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3ViX2NhdGVnb3J5KSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBzdW0obl9zdWJfY2F0KSkgJT4lIA0KICBkcGx5cjo6YXJyYW5nZShuKSAlPiUgDQogIGRwbHlyOjpwdWxsKHN1Yl9jYXRlZ29yeSkNCg0KYW50aXByZWRhdG9yX3N1YmNhdCA8LSBiZWhhdl9zdWJfY2F0X3N1bW1hcnkgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKHBhcmVudF9jYXRlZ29yeSA9PSAiYW50aXByZWRhdG9yIikgJT4lIA0KICBkcGx5cjo6c2VsZWN0KHN0dWR5X21vdGl2YXRpb24sIHN1Yl9jYXRlZ29yeSwgcGVyY2VudF9zdWJfY2F0LCBuX3N1Yl9jYXQsIHBlcmNlbnRfcGFyZW50KSAlPiUgDQogIHRpZHlyOjpjb21wbGV0ZShzdWJfY2F0ZWdvcnksIHN0dWR5X21vdGl2YXRpb24sIGZpbGwgPSBsaXN0KHBlcmNlbnRfc3ViX2NhdCA9IDAsIG5fc3ViX2NhdCA9IDApKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoc3ViX2NhdGVnb3J5ID0gZmFjdG9yKHN1Yl9jYXRlZ29yeSwgbGV2ZWxzID0gc3ViX2NhdGVnb3J5X29yZGVyKSkNCmBgYA0KDQoNCmBgYHtyfQ0KYmVoX2FudGlwcmVkYXRvcl9zdWJjYXRfZmlnIDwtIGFudGlwcmVkYXRvcl9zdWJjYXQgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHBlcmNlbnRfc3ViX2NhdCA9IHJvdW5kKHBlcmNlbnRfc3ViX2NhdCwzKSoxMDApICU+JSANCiAgZ2dwbG90KGFlcyh4PXN1Yl9jYXRlZ29yeSwgeT1wZXJjZW50X3N1Yl9jYXQsIGNvbG91ciA9IHN0dWR5X21vdGl2YXRpb24sIGZpbGwgPSBzdHVkeV9tb3RpdmF0aW9uLCBncm91cCA9IHN0dWR5X21vdGl2YXRpb24pKSArDQogIGdlb21fY29sKHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjgpLCB3aWR0aCA9IDAuMSkgKw0KICBnZW9tX3BvaW50KHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjgpLCBzaXplID0gMykgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGVyY2VudF9zdWJfY2F0KSwgaGp1c3Q9LTAuNiwgc2l6ZT0zLjUsIGNvbG9yPSJibGFjayIsIHBvc2l0aW9uID0gIHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC44KSkgKw0KICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IG1vdGl2YXRpb25fY29sb3VyX3RoZW1lLCBuYW1lID0gIlN0dWR5IG1vdGl2YXRpb24iKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IG1vdGl2YXRpb25fY29sb3VyX3RoZW1lLCBuYW1lID0gIlN0dWR5IG1vdGl2YXRpb24iKSArDQogIHRoZW1lX2NsYXNzaWMoKSArDQogIGNvb3JkX2ZsaXAoKSArDQogICBsYWJzKA0KICAgIHggPSAiIiwNCiAgICB5ID0gIlBlcmNlbnRhZ2Ugb2YgZGF0YSINCiAgKSArDQogICB0aGVtZSgNCiAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiDQogICApDQoNCmJlaF9hbnRpcHJlZGF0b3Jfc3ViY2F0X2ZpZw0KYGBgDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQ0Kbl9zdWJjYXQgPC0gYW50aXByZWRhdG9yX3N1YmNhdCAlPiUgDQogIGRwbHlyOjpkaXN0aW5jdChzdWJfY2F0ZWdvcnkpICU+JSANCiAgbnJvdyguKS8xMA0KDQpzZXR3ZChmaWd1cmVzX3BhdGgpDQpnZ3NhdmUoImJlaF9hbnRpcHJlZGF0b3Jfc3ViY2F0X2ZpZy5wZGYiLCBwbG90ID0gYmVoX2FudGlwcmVkYXRvcl9zdWJjYXRfZmlnLCB3aWR0aCA9IDEwLCBoZWlnaHQgPSAxMS43Km5fc3ViY2F0KQ0KYGBgDQoNCg0KIyMjIDE0LjIuNSBNYXRpbmcgcGxvdHMgDQoNCmBgYHtyfQ0Kc3ViX2NhdGVnb3J5X29yZGVyIDwtIGJlaGF2X3N1Yl9jYXRfc3VtbWFyeSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIocGFyZW50X2NhdGVnb3J5ID09ICJtYXRpbmciKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzdWJfY2F0ZWdvcnkpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IHN1bShuX3N1Yl9jYXQpKSAlPiUgDQogIGRwbHlyOjphcnJhbmdlKG4pICU+JSANCiAgZHBseXI6OnB1bGwoc3ViX2NhdGVnb3J5KQ0KDQptYXRpbmdfc3ViY2F0IDwtIGJlaGF2X3N1Yl9jYXRfc3VtbWFyeSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIocGFyZW50X2NhdGVnb3J5ID09ICJtYXRpbmciKSAlPiUgDQogIGRwbHlyOjpzZWxlY3Qoc3R1ZHlfbW90aXZhdGlvbiwgc3ViX2NhdGVnb3J5LCBwZXJjZW50X3N1Yl9jYXQsIG5fc3ViX2NhdCwgcGVyY2VudF9wYXJlbnQpICU+JSANCiAgdGlkeXI6OmNvbXBsZXRlKHN1Yl9jYXRlZ29yeSwgc3R1ZHlfbW90aXZhdGlvbiwgZmlsbCA9IGxpc3QocGVyY2VudF9zdWJfY2F0ID0gMCwgbl9zdWJfY2F0ID0gMCkpICU+JSANCiAgZHBseXI6Om11dGF0ZShzdWJfY2F0ZWdvcnkgPSBmYWN0b3Ioc3ViX2NhdGVnb3J5LCBsZXZlbHMgPSBzdWJfY2F0ZWdvcnlfb3JkZXIpKQ0KYGBgDQoNCg0KYGBge3J9DQpiZWhfbWF0aW5nX3N1YmNhdF9maWcgPC0gbWF0aW5nX3N1YmNhdCAlPiUgDQogIGRwbHlyOjptdXRhdGUocGVyY2VudF9zdWJfY2F0ID0gcm91bmQocGVyY2VudF9zdWJfY2F0LDMpKjEwMCkgJT4lIA0KICBnZ3Bsb3QoYWVzKHg9c3ViX2NhdGVnb3J5LCB5PXBlcmNlbnRfc3ViX2NhdCwgY29sb3VyID0gc3R1ZHlfbW90aXZhdGlvbiwgZmlsbCA9IHN0dWR5X21vdGl2YXRpb24sIGdyb3VwID0gc3R1ZHlfbW90aXZhdGlvbikpICsNCiAgZ2VvbV9jb2wocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOCksIHdpZHRoID0gMC4xKSArDQogIGdlb21fcG9pbnQocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOCksIHNpemUgPSAzKSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBwZXJjZW50X3N1Yl9jYXQpLCBoanVzdD0tMC42LCBzaXplPTMuNSwgY29sb3I9ImJsYWNrIiwgcG9zaXRpb24gPSAgcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjgpKSArDQogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gbW90aXZhdGlvbl9jb2xvdXJfdGhlbWUsIG5hbWUgPSAiU3R1ZHkgbW90aXZhdGlvbiIpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gbW90aXZhdGlvbl9jb2xvdXJfdGhlbWUsIG5hbWUgPSAiU3R1ZHkgbW90aXZhdGlvbiIpICsNCiAgdGhlbWVfY2xhc3NpYygpICsNCiAgY29vcmRfZmxpcCgpICsNCiAgIGxhYnMoDQogICAgeCA9ICIiLA0KICAgIHkgPSAiUGVyY2VudGFnZSBvZiBkYXRhIg0KICApICsNCiAgIHRoZW1lKA0KICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSINCiAgICkNCg0KYmVoX21hdGluZ19zdWJjYXRfZmlnDQpgYGANCg0KDQoNCg0KYGBge3IsIHdhcm5pbmc9RkFMU0V9DQpuX3N1YmNhdCA8LSBtYXRpbmdfc3ViY2F0ICU+JSANCiAgZHBseXI6OmRpc3RpbmN0KHN1Yl9jYXRlZ29yeSkgJT4lIA0KICBucm93KC4pLzEwDQoNCnNldHdkKGZpZ3VyZXNfcGF0aCkNCmdnc2F2ZSgiYmVoX21hdGluZ19zdWJjYXRfZmlnLnBkZiIsIHBsb3QgPSBiZWhfbWF0aW5nX3N1YmNhdF9maWcsIHdpZHRoID0gMTAsIGhlaWdodCA9IDExLjcqbl9zdWJjYXQpDQpgYGANCg0KDQojIyMgMTQuMi42IFBvc3QgbWF0aW5nIHBsb3RzIA0KDQpgYGB7cn0NCnN1Yl9jYXRlZ29yeV9vcmRlciA8LSBiZWhhdl9zdWJfY2F0X3N1bW1hcnkgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKHBhcmVudF9jYXRlZ29yeSA9PSAicG9zdF9tYXRpbmciKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzdWJfY2F0ZWdvcnkpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IHN1bShuX3N1Yl9jYXQpKSAlPiUgDQogIGRwbHlyOjphcnJhbmdlKG4pICU+JSANCiAgZHBseXI6OnB1bGwoc3ViX2NhdGVnb3J5KQ0KDQpwb3N0X21hdGluZ19zdWJjYXQgPC0gYmVoYXZfc3ViX2NhdF9zdW1tYXJ5ICU+JSANCiAgZHBseXI6OmZpbHRlcihwYXJlbnRfY2F0ZWdvcnkgPT0gInBvc3RfbWF0aW5nIikgJT4lIA0KICBkcGx5cjo6c2VsZWN0KHN0dWR5X21vdGl2YXRpb24sIHN1Yl9jYXRlZ29yeSwgcGVyY2VudF9zdWJfY2F0LCBuX3N1Yl9jYXQsIHBlcmNlbnRfcGFyZW50KSAlPiUgDQogIHRpZHlyOjpjb21wbGV0ZShzdWJfY2F0ZWdvcnksIHN0dWR5X21vdGl2YXRpb24sIGZpbGwgPSBsaXN0KHBlcmNlbnRfc3ViX2NhdCA9IDAsIG5fc3ViX2NhdCA9IDApKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoc3ViX2NhdGVnb3J5ID0gZmFjdG9yKHN1Yl9jYXRlZ29yeSwgbGV2ZWxzID0gc3ViX2NhdGVnb3J5X29yZGVyKSkNCmBgYA0KDQoNCmBgYHtyfQ0KYmVoX3Bvc3RfbWF0aW5nX3N1YmNhdF9maWcgPC0gcG9zdF9tYXRpbmdfc3ViY2F0ICU+JSANCiAgZHBseXI6Om11dGF0ZShwZXJjZW50X3N1Yl9jYXQgPSByb3VuZChwZXJjZW50X3N1Yl9jYXQsMykqMTAwKSAlPiUgDQogIGdncGxvdChhZXMoeD1zdWJfY2F0ZWdvcnksIHk9cGVyY2VudF9zdWJfY2F0LCBjb2xvdXIgPSBzdHVkeV9tb3RpdmF0aW9uLCBmaWxsID0gc3R1ZHlfbW90aXZhdGlvbiwgZ3JvdXAgPSBzdHVkeV9tb3RpdmF0aW9uKSkgKw0KICBnZW9tX2NvbChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC44KSwgd2lkdGggPSAwLjEpICsNCiAgZ2VvbV9wb2ludChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC44KSwgc2l6ZSA9IDMpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHBlcmNlbnRfc3ViX2NhdCksIGhqdXN0PS0wLjYsIHNpemU9My41LCBjb2xvcj0iYmxhY2siLCBwb3NpdGlvbiA9ICBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOCkpICsNCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBtb3RpdmF0aW9uX2NvbG91cl90aGVtZSwgbmFtZSA9ICJTdHVkeSBtb3RpdmF0aW9uIikgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBtb3RpdmF0aW9uX2NvbG91cl90aGVtZSwgbmFtZSA9ICJTdHVkeSBtb3RpdmF0aW9uIikgKw0KICB0aGVtZV9jbGFzc2ljKCkgKw0KICBjb29yZF9mbGlwKCkgKw0KICAgbGFicygNCiAgICB4ID0gIiIsDQogICAgeSA9ICJQZXJjZW50YWdlIG9mIGRhdGEiDQogICkgKw0KICAgdGhlbWUoDQogICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIg0KICAgKQ0KDQpiZWhfcG9zdF9tYXRpbmdfc3ViY2F0X2ZpZw0KYGBgDQoNCg0KYGBge3IsIHdhcm5pbmc9RkFMU0V9DQpuX3N1YmNhdCA8LSBwb3N0X21hdGluZ19zdWJjYXQgJT4lIA0KICBkcGx5cjo6ZGlzdGluY3Qoc3ViX2NhdGVnb3J5KSAlPiUgDQogIG5yb3coLikvMTANCg0Kc2V0d2QoZmlndXJlc19wYXRoKQ0KZ2dzYXZlKCJiZWhfcG9zdF9tYXRpbmdfc3ViY2F0X2ZpZy5wZGYiLCBwbG90ID0gYmVoX3Bvc3RfbWF0aW5nX3N1YmNhdF9maWcsIHdpZHRoID0gMTAsIGhlaWdodCA9IDExLjcqbl9zdWJjYXQpDQpgYGANCg0KDQojIyMgMTQuMi43IEFncmVzc2lvbiBwbG90cyANCg0KYGBge3J9DQpzdWJfY2F0ZWdvcnlfb3JkZXIgPC0gYmVoYXZfc3ViX2NhdF9zdW1tYXJ5ICU+JSANCiAgZHBseXI6OmZpbHRlcihwYXJlbnRfY2F0ZWdvcnkgPT0gImFncmVzc2lvbiIpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHN1Yl9jYXRlZ29yeSkgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gc3VtKG5fc3ViX2NhdCkpICU+JSANCiAgZHBseXI6OmFycmFuZ2UobikgJT4lIA0KICBkcGx5cjo6cHVsbChzdWJfY2F0ZWdvcnkpDQoNCmFncmVzc2lvbl9zdWJjYXQgPC0gYmVoYXZfc3ViX2NhdF9zdW1tYXJ5ICU+JSANCiAgZHBseXI6OmZpbHRlcihwYXJlbnRfY2F0ZWdvcnkgPT0gImFncmVzc2lvbiIpICU+JSANCiAgZHBseXI6OnNlbGVjdChzdHVkeV9tb3RpdmF0aW9uLCBzdWJfY2F0ZWdvcnksIHBlcmNlbnRfc3ViX2NhdCwgbl9zdWJfY2F0LCBwZXJjZW50X3BhcmVudCkgJT4lIA0KICB0aWR5cjo6Y29tcGxldGUoc3ViX2NhdGVnb3J5LCBzdHVkeV9tb3RpdmF0aW9uLCBmaWxsID0gbGlzdChwZXJjZW50X3N1Yl9jYXQgPSAwLCBuX3N1Yl9jYXQgPSAwKSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHN1Yl9jYXRlZ29yeSA9IGZhY3RvcihzdWJfY2F0ZWdvcnksIGxldmVscyA9IHN1Yl9jYXRlZ29yeV9vcmRlcikpDQpgYGANCg0KDQpgYGB7cn0NCmJlaF9hZ3Jlc3Npb25fc3ViY2F0X2ZpZyA8LSBhZ3Jlc3Npb25fc3ViY2F0ICU+JSANCiAgZHBseXI6Om11dGF0ZShwZXJjZW50X3N1Yl9jYXQgPSByb3VuZChwZXJjZW50X3N1Yl9jYXQsMykqMTAwKSAlPiUgDQogIGdncGxvdChhZXMoeD1zdWJfY2F0ZWdvcnksIHk9cGVyY2VudF9zdWJfY2F0LCBjb2xvdXIgPSBzdHVkeV9tb3RpdmF0aW9uLCBmaWxsID0gc3R1ZHlfbW90aXZhdGlvbiwgZ3JvdXAgPSBzdHVkeV9tb3RpdmF0aW9uKSkgKw0KICBnZW9tX2NvbChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC44KSwgd2lkdGggPSAwLjEpICsNCiAgZ2VvbV9wb2ludChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC44KSwgc2l6ZSA9IDMpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHBlcmNlbnRfc3ViX2NhdCksIGhqdXN0PS0wLjYsIHNpemU9My41LCBjb2xvcj0iYmxhY2siLCBwb3NpdGlvbiA9ICBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOCkpICsNCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBtb3RpdmF0aW9uX2NvbG91cl90aGVtZSwgbmFtZSA9ICJTdHVkeSBtb3RpdmF0aW9uIikgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBtb3RpdmF0aW9uX2NvbG91cl90aGVtZSwgbmFtZSA9ICJTdHVkeSBtb3RpdmF0aW9uIikgKw0KICB0aGVtZV9jbGFzc2ljKCkgKw0KICBjb29yZF9mbGlwKCkgKw0KICAgbGFicygNCiAgICB4ID0gIiIsDQogICAgeSA9ICJQZXJjZW50YWdlIG9mIGRhdGEiDQogICkgKw0KICAgdGhlbWUoDQogICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIg0KICAgKQ0KDQpiZWhfYWdyZXNzaW9uX3N1YmNhdF9maWcNCmBgYA0KDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQ0Kbl9zdWJjYXQgPC0gYWdyZXNzaW9uX3N1YmNhdCAlPiUgDQogIGRwbHlyOjpkaXN0aW5jdChzdWJfY2F0ZWdvcnkpICU+JSANCiAgbnJvdyguKS8xMA0KDQpzZXR3ZChmaWd1cmVzX3BhdGgpDQpnZ3NhdmUoImJlaF9hZ3Jlc3Npb25fc3ViY2F0X2ZpZy5wZGYiLCBwbG90ID0gYmVoX2FncmVzc2lvbl9zdWJjYXRfZmlnLCB3aWR0aCA9IDEwLCBoZWlnaHQgPSAxMS43Km5fc3ViY2F0KQ0KYGBgDQoNCg0KIyMjIDE0LjIuOCBTb2NpYWxpdHkgcGxvdHMgDQoNCmBgYHtyfQ0Kc3ViX2NhdGVnb3J5X29yZGVyIDwtIGJlaGF2X3N1Yl9jYXRfc3VtbWFyeSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIocGFyZW50X2NhdGVnb3J5ID09ICJzb2NpYWxpdHkiKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzdWJfY2F0ZWdvcnkpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IHN1bShuX3N1Yl9jYXQpKSAlPiUgDQogIGRwbHlyOjphcnJhbmdlKG4pICU+JSANCiAgZHBseXI6OnB1bGwoc3ViX2NhdGVnb3J5KQ0KDQpzb2NpYWxpdHlfc3ViY2F0IDwtIGJlaGF2X3N1Yl9jYXRfc3VtbWFyeSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIocGFyZW50X2NhdGVnb3J5ID09ICJzb2NpYWxpdHkiKSAlPiUgDQogIGRwbHlyOjpzZWxlY3Qoc3R1ZHlfbW90aXZhdGlvbiwgc3ViX2NhdGVnb3J5LCBwZXJjZW50X3N1Yl9jYXQsIG5fc3ViX2NhdCwgcGVyY2VudF9wYXJlbnQpICU+JSANCiAgdGlkeXI6OmNvbXBsZXRlKHN1Yl9jYXRlZ29yeSwgc3R1ZHlfbW90aXZhdGlvbiwgZmlsbCA9IGxpc3QocGVyY2VudF9zdWJfY2F0ID0gMCwgbl9zdWJfY2F0ID0gMCkpICU+JSANCiAgZHBseXI6Om11dGF0ZShzdWJfY2F0ZWdvcnkgPSBmYWN0b3Ioc3ViX2NhdGVnb3J5LCBsZXZlbHMgPSBzdWJfY2F0ZWdvcnlfb3JkZXIpKQ0KYGBgDQoNCg0KYGBge3J9DQpiZWhfc29jaWFsaXR5X3N1YmNhdF9maWcgPC0gc29jaWFsaXR5X3N1YmNhdCAlPiUgDQogIGRwbHlyOjptdXRhdGUocGVyY2VudF9zdWJfY2F0ID0gcm91bmQocGVyY2VudF9zdWJfY2F0LDMpKjEwMCkgJT4lIA0KICBnZ3Bsb3QoYWVzKHg9c3ViX2NhdGVnb3J5LCB5PXBlcmNlbnRfc3ViX2NhdCwgY29sb3VyID0gc3R1ZHlfbW90aXZhdGlvbiwgZmlsbCA9IHN0dWR5X21vdGl2YXRpb24sIGdyb3VwID0gc3R1ZHlfbW90aXZhdGlvbikpICsNCiAgZ2VvbV9jb2wocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOCksIHdpZHRoID0gMC4xKSArDQogIGdlb21fcG9pbnQocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOCksIHNpemUgPSAzKSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBwZXJjZW50X3N1Yl9jYXQpLCBoanVzdD0tMC42LCBzaXplPTMuNSwgY29sb3I9ImJsYWNrIiwgcG9zaXRpb24gPSAgcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjgpKSArDQogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gbW90aXZhdGlvbl9jb2xvdXJfdGhlbWUsIG5hbWUgPSAiU3R1ZHkgbW90aXZhdGlvbiIpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gbW90aXZhdGlvbl9jb2xvdXJfdGhlbWUsIG5hbWUgPSAiU3R1ZHkgbW90aXZhdGlvbiIpICsNCiAgdGhlbWVfY2xhc3NpYygpICsNCiAgY29vcmRfZmxpcCgpICsNCiAgIGxhYnMoDQogICAgeCA9ICIiLA0KICAgIHkgPSAiUGVyY2VudGFnZSBvZiBkYXRhIg0KICApICsNCiAgIHRoZW1lKA0KICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSINCiAgICkNCg0KYmVoX3NvY2lhbGl0eV9zdWJjYXRfZmlnDQpgYGANCg0KDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCm5fc3ViY2F0IDwtIHNvY2lhbGl0eV9zdWJjYXQgJT4lIA0KICBkcGx5cjo6ZGlzdGluY3Qoc3ViX2NhdGVnb3J5KSAlPiUgDQogIG5yb3coLikvMTANCg0Kc2V0d2QoZmlndXJlc19wYXRoKQ0KZ2dzYXZlKCJiZWhfc29jaWFsaXR5X3N1YmNhdF9maWcucGRmIiwgcGxvdCA9IGJlaF9zb2NpYWxpdHlfc3ViY2F0X2ZpZywgd2lkdGggPSAxMCwgaGVpZ2h0ID0gMTEuNypuX3N1YmNhdCkNCmBgYA0KDQoNCiMjIyAxNC4yLjkgQ29nbml0aW9uIHBsb3RzIA0KDQpgYGB7cn0NCnN1Yl9jYXRlZ29yeV9vcmRlciA8LSBiZWhhdl9zdWJfY2F0X3N1bW1hcnkgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKHBhcmVudF9jYXRlZ29yeSA9PSAiY29nbml0aW9uIikgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3ViX2NhdGVnb3J5KSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBzdW0obl9zdWJfY2F0KSkgJT4lIA0KICBkcGx5cjo6YXJyYW5nZShuKSAlPiUgDQogIGRwbHlyOjpwdWxsKHN1Yl9jYXRlZ29yeSkNCg0KY29nbml0aW9uX3N1YmNhdCA8LSBiZWhhdl9zdWJfY2F0X3N1bW1hcnkgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKHBhcmVudF9jYXRlZ29yeSA9PSAiY29nbml0aW9uIikgJT4lIA0KICBkcGx5cjo6c2VsZWN0KHN0dWR5X21vdGl2YXRpb24sIHN1Yl9jYXRlZ29yeSwgcGVyY2VudF9zdWJfY2F0LCBuX3N1Yl9jYXQsIHBlcmNlbnRfcGFyZW50KSAlPiUgDQogIHRpZHlyOjpjb21wbGV0ZShzdWJfY2F0ZWdvcnksIHN0dWR5X21vdGl2YXRpb24sIGZpbGwgPSBsaXN0KHBlcmNlbnRfc3ViX2NhdCA9IDAsIG5fc3ViX2NhdCA9IDApKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoc3ViX2NhdGVnb3J5ID0gZmFjdG9yKHN1Yl9jYXRlZ29yeSwgbGV2ZWxzID0gc3ViX2NhdGVnb3J5X29yZGVyKSkNCmBgYA0KDQoNCmBgYHtyfQ0KYmVoX2NvZ25pdGlvbl9zdWJjYXRfZmlnIDwtIGNvZ25pdGlvbl9zdWJjYXQgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHBlcmNlbnRfc3ViX2NhdCA9IHJvdW5kKHBlcmNlbnRfc3ViX2NhdCwzKSoxMDApICU+JSANCiAgZ2dwbG90KGFlcyh4PXN1Yl9jYXRlZ29yeSwgeT1wZXJjZW50X3N1Yl9jYXQsIGNvbG91ciA9IHN0dWR5X21vdGl2YXRpb24sIGZpbGwgPSBzdHVkeV9tb3RpdmF0aW9uLCBncm91cCA9IHN0dWR5X21vdGl2YXRpb24pKSArDQogIGdlb21fY29sKHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjgpLCB3aWR0aCA9IDAuMSkgKw0KICBnZW9tX3BvaW50KHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjgpLCBzaXplID0gMykgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGVyY2VudF9zdWJfY2F0KSwgaGp1c3Q9LTAuNiwgc2l6ZT0zLjUsIGNvbG9yPSJibGFjayIsIHBvc2l0aW9uID0gIHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC44KSkgKw0KICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IG1vdGl2YXRpb25fY29sb3VyX3RoZW1lLCBuYW1lID0gIlN0dWR5IG1vdGl2YXRpb24iKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IG1vdGl2YXRpb25fY29sb3VyX3RoZW1lLCBuYW1lID0gIlN0dWR5IG1vdGl2YXRpb24iKSArDQogIHRoZW1lX2NsYXNzaWMoKSArDQogIGNvb3JkX2ZsaXAoKSArDQogICBsYWJzKA0KICAgIHggPSAiIiwNCiAgICB5ID0gIlBlcmNlbnRhZ2Ugb2YgZGF0YSINCiAgKSArDQogICB0aGVtZSgNCiAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiDQogICApDQoNCmJlaF9jb2duaXRpb25fc3ViY2F0X2ZpZw0KYGBgDQoNCg0KYGBge3IsIHdhcm5pbmc9RkFMU0V9DQpuX3N1YmNhdCA8LSBjb2duaXRpb25fc3ViY2F0ICU+JSANCiAgZHBseXI6OmRpc3RpbmN0KHN1Yl9jYXRlZ29yeSkgJT4lIA0KICBucm93KC4pLzEwDQoNCnNldHdkKGZpZ3VyZXNfcGF0aCkNCmdnc2F2ZSgiYmVoX2NvZ25pdGlvbl9zdWJjYXRfZmlnLnBkZiIsIHBsb3QgPSBiZWhfY29nbml0aW9uX3N1YmNhdF9maWcsIHdpZHRoID0gMTAsIGhlaWdodCA9IDExLjcqbl9zdWJjYXQpDQpgYGANCg0KIyMjIDE0LjIuMTAgTm9uLWNhdGVnb3JpZXMgcGxvdHMgDQoNCmBgYHtyfQ0Kc3ViX2NhdGVnb3J5X29yZGVyIDwtIGJlaGF2X3N1Yl9jYXRfc3VtbWFyeSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIocGFyZW50X2NhdGVnb3J5ID09ICJub25jYXQiKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzdWJfY2F0ZWdvcnkpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IHN1bShuX3N1Yl9jYXQpKSAlPiUgDQogIGRwbHlyOjphcnJhbmdlKG4pICU+JSANCiAgZHBseXI6OnB1bGwoc3ViX2NhdGVnb3J5KQ0KDQpub25jYXRfc3ViY2F0IDwtIGJlaGF2X3N1Yl9jYXRfc3VtbWFyeSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIocGFyZW50X2NhdGVnb3J5ID09ICJub25jYXQiKSAlPiUgDQogIGRwbHlyOjpzZWxlY3Qoc3R1ZHlfbW90aXZhdGlvbiwgc3ViX2NhdGVnb3J5LCBwZXJjZW50X3N1Yl9jYXQsIG5fc3ViX2NhdCwgcGVyY2VudF9wYXJlbnQpICU+JSANCiAgdGlkeXI6OmNvbXBsZXRlKHN1Yl9jYXRlZ29yeSwgc3R1ZHlfbW90aXZhdGlvbiwgZmlsbCA9IGxpc3QocGVyY2VudF9zdWJfY2F0ID0gMCwgbl9zdWJfY2F0ID0gMCkpICU+JSANCiAgZHBseXI6Om11dGF0ZShzdWJfY2F0ZWdvcnkgPSBmYWN0b3Ioc3ViX2NhdGVnb3J5LCBsZXZlbHMgPSBzdWJfY2F0ZWdvcnlfb3JkZXIpKQ0KYGBgDQoNCg0KYGBge3J9DQpiZWhfbm9uY2F0X3N1YmNhdF9maWcgPC0gbm9uY2F0X3N1YmNhdCAlPiUgDQogIGRwbHlyOjptdXRhdGUocGVyY2VudF9zdWJfY2F0ID0gcm91bmQocGVyY2VudF9zdWJfY2F0LDMpKjEwMCkgJT4lIA0KICBnZ3Bsb3QoYWVzKHg9c3ViX2NhdGVnb3J5LCB5PXBlcmNlbnRfc3ViX2NhdCwgY29sb3VyID0gc3R1ZHlfbW90aXZhdGlvbiwgZmlsbCA9IHN0dWR5X21vdGl2YXRpb24sIGdyb3VwID0gc3R1ZHlfbW90aXZhdGlvbikpICsNCiAgZ2VvbV9jb2wocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOCksIHdpZHRoID0gMC4xKSArDQogIGdlb21fcG9pbnQocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOCksIHNpemUgPSAzKSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBwZXJjZW50X3N1Yl9jYXQpLCBoanVzdD0tMC42LCBzaXplPTMuNSwgY29sb3I9ImJsYWNrIiwgcG9zaXRpb24gPSAgcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjgpKSArDQogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gbW90aXZhdGlvbl9jb2xvdXJfdGhlbWUsIG5hbWUgPSAiU3R1ZHkgbW90aXZhdGlvbiIpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gbW90aXZhdGlvbl9jb2xvdXJfdGhlbWUsIG5hbWUgPSAiU3R1ZHkgbW90aXZhdGlvbiIpICsNCiAgdGhlbWVfY2xhc3NpYygpICsNCiAgY29vcmRfZmxpcCgpICsNCiAgIGxhYnMoDQogICAgeCA9ICIiLA0KICAgIHkgPSAiUGVyY2VudGFnZSBvZiBkYXRhIg0KICApICsNCiAgIHRoZW1lKA0KICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSINCiAgICkNCg0KYmVoX25vbmNhdF9zdWJjYXRfZmlnDQpgYGANCg0KDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCm5fc3ViY2F0IDwtIG5vbmNhdF9zdWJjYXQgJT4lIA0KICBkcGx5cjo6ZGlzdGluY3Qoc3ViX2NhdGVnb3J5KSAlPiUgDQogIG5yb3coLikvMTANCg0Kc2V0d2QoZmlndXJlc19wYXRoKQ0KZ2dzYXZlKCJiZWhfbm9uY2F0X3N1YmNhdF9maWcucGRmIiwgcGxvdCA9IGJlaF9ub25jYXRfc3ViY2F0X2ZpZywgd2lkdGggPSAxMCwgaGVpZ2h0ID0gMTEuNypuX3N1YmNhdCkNCmBgYA0KDQoNCiMjIDE0LjMgQmVoYXZpb3VyIGxvY2F0aW9uIA0KDQpDaGVjayB3aGVyZSBiZWhhdmlvdXIgd2FzIG1lYXNzdXJlZC4NCg0KYGBge3J9DQpiZWhhdl9sb2NhdGlvbl9zdW1tYXJ5IDwtIEVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uLCBiZWhhdl90ZXN0X2xvY2F0aW9uKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBuKCkpICU+JSANCiAgdGlkeXI6OnNlcGFyYXRlX3Jvd3MoYmVoYXZfdGVzdF9sb2NhdGlvbiwgc2VwID0gIjsiKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uLCBiZWhhdl90ZXN0X2xvY2F0aW9uKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBzdW0obikpICU+JSANCiAgdGlkeXI6OmNvbXBsZXRlKGJlaGF2X3Rlc3RfbG9jYXRpb24sIHN0dWR5X21vdGl2YXRpb24sIGZpbGwgPSBsaXN0KG4gPSAwKSkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHRvdGFsX21vdGl2YXRpb24gPSBzdW0obikpICU+JSANCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjptdXRhdGUocGVyY2VudCA9IHJvdW5kKG4vdG90YWxfbW90aXZhdGlvbioxMDAsMSkpICU+JSANCiAgZHBseXI6OnNlbGVjdCgtdG90YWxfbW90aXZhdGlvbikNCg0KYmVoYXZfbG9jYXRpb25fb3ZlcmFsbCA8LSBiZWhhdl9sb2NhdGlvbl9zdW1tYXJ5ICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KGJlaGF2X3Rlc3RfbG9jYXRpb24pICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IHN1bShuKSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHBlcmNlbnQgPSByb3VuZChuL3N1bShuKSoxMDAsMSksDQogICAgICAgICAgICAgICAgc3R1ZHlfbW90aXZhdGlvbiA9ICJPdmVyYWxsIikNCg0KYmVoYXZfbG9jYXRpb25fc3VtbWFyeSA8LSAgcmJpbmQoYmVoYXZfbG9jYXRpb25fb3ZlcmFsbCwgYmVoYXZfbG9jYXRpb25fc3VtbWFyeSkgJT4lIA0KICBkcGx5cjo6YXJyYW5nZShzdHVkeV9tb3RpdmF0aW9uKQ0KDQpiZWhhdl9sb2NhdGlvbl9zdW1tYXJ5DQpgYGANCg0KDQojIyAxNC40IFNvY2lhbCBjb250ZXh0DQoNCkNoZWNrIGhvdyBvZnRlbiBiZWhhdmlvdXIgd2FzIG1lYXN1cmVkIGluIGEgc29jaWFsIGNvbnRleHQNCg0KDQpgYGB7cn0NCmJlaGF2X3NvY2lhbF9jb250ZXh0X3N1bW1hcnkgPC0gRUlQQUFCX2RhdGFiYXNlICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHN0dWR5X21vdGl2YXRpb24sIGJlaGF2X2lzX3NvY2lhbF9jb250ZXh0KSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBuKCkpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHN0dWR5X21vdGl2YXRpb24pICU+JSANCiAgZHBseXI6Om11dGF0ZSh0b3RhbF9tb3RpdmF0aW9uID0gc3VtKG4pKSAlPiUgDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHBlcmNlbnQgPSByb3VuZChuL3RvdGFsX21vdGl2YXRpb24qMTAwLDEpKSAlPiUgDQogIGRwbHlyOjpzZWxlY3QoLXRvdGFsX21vdGl2YXRpb24pDQoNCmJlaGF2X3NvY2lhbF9jb250ZXh0X292ZXJhbGwgPC0gYmVoYXZfc29jaWFsX2NvbnRleHRfc3VtbWFyeSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShiZWhhdl9pc19zb2NpYWxfY29udGV4dCkgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gc3VtKG4pKSAlPiUgDQogIGRwbHlyOjptdXRhdGUocGVyY2VudCA9IHJvdW5kKG4vc3VtKG4pKjEwMCwxKSwNCiAgICAgICAgICAgICAgICBzdHVkeV9tb3RpdmF0aW9uID0gIk92ZXJhbGwiKQ0KDQpiZWhhdl9zb2NpYWxfY29udGV4dF9zdW1tYXJ5IDwtICByYmluZChiZWhhdl9zb2NpYWxfY29udGV4dF9vdmVyYWxsLCBiZWhhdl9zb2NpYWxfY29udGV4dF9zdW1tYXJ5KSAlPiUgDQogIGRwbHlyOjphcnJhbmdlKHN0dWR5X21vdGl2YXRpb24pDQoNCmJlaGF2X3NvY2lhbF9jb250ZXh0X3N1bW1hcnkNCmBgYA0KDQoNCiMjIDE0LjUgQ2hlY2sgaG93IGJlaGF2aW91ciB3YXMgbWVhc3N1cmVkDQoNCkNoZWNrIGhvdyBvZnRlbiBiZWhhdmlvdXIgd2FzIG1lYXNzdXJlZCBpbiBhIHNvY2lhbCBjb250ZXh0DQoNCmBgYHtyfQ0KYmVoYXZfYmVoYXZfc2NvcmluZ19zdW1tYXJ5IDwtIEVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShhcnRpY2xlX2lkKSAlPiUgDQogIGRwbHlyOjpzYW1wbGVfbigxKSAlPiUgDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3R1ZHlfbW90aXZhdGlvbiwgdmFsaWRpdHlfYmVoYXZfc2NvcmluZ19tZXRob2QpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IG4oKSkgJT4lIA0KICB0aWR5cjo6c2VwYXJhdGVfcm93cyh2YWxpZGl0eV9iZWhhdl9zY29yaW5nX21ldGhvZCwgc2VwID0gIjsiKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uLCB2YWxpZGl0eV9iZWhhdl9zY29yaW5nX21ldGhvZCkgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gc3VtKG4pKSAlPiUgDQogIHRpZHlyOjpjb21wbGV0ZSh2YWxpZGl0eV9iZWhhdl9zY29yaW5nX21ldGhvZCwgc3R1ZHlfbW90aXZhdGlvbiwgZmlsbCA9IGxpc3QobiA9IDApKSAlPiUNCiAgZHBseXI6Omdyb3VwX2J5KHN0dWR5X21vdGl2YXRpb24pICU+JSANCiAgZHBseXI6Om11dGF0ZSh0b3RhbF9tb3RpdmF0aW9uID0gc3VtKG4pKSAlPiUgDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHBlcmNlbnQgPSByb3VuZChuL3RvdGFsX21vdGl2YXRpb24qMTAwLDEpKSAlPiUgDQogIGRwbHlyOjpzZWxlY3QoLXRvdGFsX21vdGl2YXRpb24pDQoNCmJlaGF2X2JlaGF2X3Njb3Jpbmdfb3ZlcmFsbCA8LSBiZWhhdl9iZWhhdl9zY29yaW5nX3N1bW1hcnkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkodmFsaWRpdHlfYmVoYXZfc2NvcmluZ19tZXRob2QpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IHN1bShuKSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHBlcmNlbnQgPSByb3VuZChuL3N1bShuKSoxMDAsMSksDQogICAgICAgICAgICAgICAgc3R1ZHlfbW90aXZhdGlvbiA9ICJPdmVyYWxsIikNCg0KYmVoYXZfYmVoYXZfc2NvcmluZ19zdW1tYXJ5IDwtICByYmluZChiZWhhdl9iZWhhdl9zY29yaW5nX292ZXJhbGwsIGJlaGF2X2JlaGF2X3Njb3Jpbmdfc3VtbWFyeSkgJT4lIA0KICBkcGx5cjo6YXJyYW5nZShzdHVkeV9tb3RpdmF0aW9uKQ0KDQpiZWhhdl9iZWhhdl9zY29yaW5nX3N1bW1hcnkNCmBgYA0KDQpgYGB7cn0NCmJlaGF2X2JlaGF2X3Njb3Jpbmdfc3VtbWFyeSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIoc3R1ZHlfbW90aXZhdGlvbiAgPT0gIk92ZXJhbGwiKQ0KYGBgDQoNCiMgMTUgTGlua2luZyBQSUNPDQoNCk1ha2luZyBhIGRhdGFmcmFtZSBmb3IgYSBmbG93IGRpYWdyYW0gKHNhbmtleSBwbG90KQ0KDQpgYGB7cn0NClBJQ09fZGYgPC0gRUlQQUFCX2RhdGFiYXNlICU+JQ0KICBkcGx5cjo6bXV0YXRlKGJlaGF2X2NhdCA9IGNhc2Vfd2hlbigNCiAgICBiZWhhdl9tb3ZlbWVudF9ib29sZWFuID09IDEgfiAiTW92ZW1lbnQiLA0KICAgIGJlaGF2X2JvbGRuZXNzX2Jvb2xlYW4gPT0gMSB+ICJCb2xkbmVzcyIsDQogICAgYmVoYXZfZm9yYWdpbmdfYm9vbGVhbiA9PSAxIH4gIkZvcmFnaW5nIiwNCiAgICBiZWhhdl9hbnRpcHJlZGF0b3JfYm9vbGVhbiA9PSAxIH4gIkFudGlwcmVkYXRvciIsDQogICAgYmVoYXZfbWF0aW5nX2Jvb2xlYW4gPT0gMSB+ICJNYXRpbmciLA0KICAgIGJlaGF2X3Bvc3RfbWF0aW5nX2Jvb2xlYW4gPT0gMSB+ICJQb3N0IG1hdGluZyIsDQogICAgYmVoYXZfYWdyZXNzaW9uX2Jvb2xlYW4gPT0gMSB+ICJBZ3Jlc3Npb24iLA0KICAgIGJlaGF2X3NvY2lhbGl0eV9ib29sZWFuID09IDEgfiAiU29jaWFsaXR5IiwNCiAgICBiZWhhdl9jb2duaXRpb25fYm9vbGVhbiA9PSAxIH4gIkNvZ25pdGlvbiIsDQogICAgYmVoYXZfbm9uY2F0X2Jvb2xlYW4gPT0gMSB+ICJOb3QgY2F0ZWdvcmlzZWQiLA0KICApKSAlPiUgDQogIGRwbHlyOjpzZWxlY3Qoc3R1ZHlfbW90aXZhdGlvbiwgY29tcG91bmRfbmFtZSwgY29tcG91bmRfYXRjX2xldmVsXzMsIHNwZWNpZXNfbmFtZSwgc3BlY2llc19jbGFzcywgYmVoYXZfY2F0KSANCmBgYA0KDQpMZXQncyBsb29rIGF0IHRoZSAxMCBtb3N0IGNvbW1vbiBjbGFzc2VzIGFuZCBBVENzDQoNCmBgYHtyfQ0KUElDT19jbGFzc19hdGMgPC0gUElDT19kZiAlPiUgDQogIGRwbHlyOjpmaWx0ZXIoIWlzLm5hKGNvbXBvdW5kX2F0Y19sZXZlbF8zKSwgIWlzLm5hKHNwZWNpZXNfY2xhc3MpKSAlPiUgDQogIHRpZHlyOjpzZXBhcmF0ZV9yb3dzKGNvbXBvdW5kX2F0Y19sZXZlbF8zLCBzZXAgPSAiOyIpICU+JSANCiAgZHBseXI6Om11dGF0ZShjb21wb3VuZF9hdGNfbGV2ZWxfMyA9IHN0cl90cmltKGNvbXBvdW5kX2F0Y19sZXZlbF8zKSkNCg0KUElDT19hdGNfMTAgPC0gUElDT19jbGFzc19hdGMgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoY29tcG91bmRfYXRjX2xldmVsXzMpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IG4oKSkgJT4lIA0KICBkcGx5cjo6YXJyYW5nZShkZXNjKG4pKSAlPiUgDQogIGRwbHlyOjpzbGljZSgxOjEwKSAlPiUgDQogIGRwbHlyOjpwdWxsKGNvbXBvdW5kX2F0Y19sZXZlbF8zKQ0KDQpQSUNPX2NsYXNzXzEwIDwtIFBJQ09fY2xhc3NfYXRjICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHNwZWNpZXNfY2xhc3MpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IG4oKSkgJT4lIA0KICBkcGx5cjo6YXJyYW5nZShkZXNjKG4pKSAlPiUgDQogIGRwbHlyOjpzbGljZSgxOjEwKSAlPiUgDQogIGRwbHlyOjpwdWxsKHNwZWNpZXNfY2xhc3MpDQoNClBJQ09fY2xhc3NfMTAgPC0gUElDT19jbGFzc19hdGMgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3BlY2llc19jbGFzcykgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gbigpKSAlPiUgDQogIGRwbHlyOjphcnJhbmdlKGRlc2MobikpICU+JSANCiAgZHBseXI6OnNsaWNlKDE6MTApICU+JSANCiAgZHBseXI6OnB1bGwoc3BlY2llc19jbGFzcykNCg0KDQpiZWhhdl9jYXRfb3JkZXIgPC0gUElDT19jbGFzc19hdGMgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKGNvbXBvdW5kX2F0Y19sZXZlbF8zICVpbiUgUElDT19hdGNfMTAgJiBzcGVjaWVzX2NsYXNzICVpbiUgUElDT19jbGFzc18xMCkgJT4lDQogIGRwbHlyOjpncm91cF9ieShiZWhhdl9jYXQpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IG4oKSkgJT4lIA0KICBkcGx5cjo6YXJyYW5nZShkZXNjKG4pKSAlPiUgDQogIGRwbHlyOjpwdWxsKGJlaGF2X2NhdCkNCg0KDQpQSUNPX2NsYXNzX2F0Y18xMCA8LSBQSUNPX2NsYXNzX2F0YyAlPiUgDQogIGRwbHlyOjpmaWx0ZXIoY29tcG91bmRfYXRjX2xldmVsXzMgJWluJSBQSUNPX2F0Y18xMCAmIHNwZWNpZXNfY2xhc3MgJWluJSBQSUNPX2NsYXNzXzEwKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoY29tcG91bmRfYXRjX2xldmVsXzMgPSBmYWN0b3IoY29tcG91bmRfYXRjX2xldmVsXzMsIGxldmVscyA9IFBJQ09fYXRjXzEwKSwNCiAgICAgICAgICAgICAgICBzcGVjaWVzX2NsYXNzID0gZmFjdG9yKHNwZWNpZXNfY2xhc3MsIGxldmVscyA9IFBJQ09fY2xhc3NfMTApLA0KICAgICAgICAgICAgICAgIGJlaGF2X2NhdCA9IGZhY3RvcihiZWhhdl9jYXQsIGxldmVscyA9IGJlaGF2X2NhdF9vcmRlcikpICU+JSANCiAgZHBseXI6OnNlbGVjdChjb21wb3VuZF9hdGNfbGV2ZWxfMywgYmVoYXZfY2F0LCBzcGVjaWVzX2NsYXNzKQ0KYGBgDQoNCg0KYGBge3J9DQpQSUNPX2F0Y19jbGFzc19zYW5rZXkgPC0gaGlnaGNoYXJ0ZXI6OmhjaGFydChkYXRhX3RvX3NhbmtleShQSUNPX2NsYXNzX2F0Y18xMCksICJzYW5rZXkiKQ0KUElDT19hdGNfY2xhc3Nfc2Fua2V5DQpgYGANCg0KYGBge3IsIHdhcm5pbmc9RkFMU0V9DQpzZXR3ZChmaWd1cmVzX3BhdGgpDQpodG1sd2lkZ2V0czo6c2F2ZVdpZGdldCh3aWRnZXQgPSBQSUNPX2F0Y19jbGFzc19zYW5rZXksIGZpbGUgPSAiUElDT19hdGNfY2xhc3Nfc2Fua2V5Lmh0bWwiKQ0KYGBgDQoNCg0KYGBge3IsIHdhcm5pbmc9RkFMU0V9DQpzZXR3ZChmaWd1cmVzX3BhdGgpDQojIE1ha2UgYSB3ZWJzaG90IGluIHBkZiA6IGhpZ2ggcXVhbGl0eSBidXQgY2FuIG5vdCBjaG9vc2UgcHJpbnRlZCB6b25lDQp3ZWJzaG90Ojp3ZWJzaG90KCJQSUNPX2F0Y19jbGFzc19zYW5rZXkuaHRtbCIgLCAiUElDT19hdGNfY2xhc3Nfc2Fua2V5LnBkZiIsIGRlbGF5ID0gMTApDQpgYGANCg0KDQojIyAxNS4xIENvbW1vbiBjb21wb3VuZHMNCg0KTGV0cyB0YWtlIGEgY2xvc2VyIGxvb2sgYXQgdGhlIDMgbW9zdCBjb21tb24gY29tcG91bmRzDQoNCmBgYHtyfQ0KRUlQQUFCX2RhdGFiYXNlICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KGNvbXBvdW5kX25hbWUpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IG4oKSkgJT4lIA0KICBkcGx5cjo6YXJyYW5nZShkZXNjKG4pKSAlPiUgDQogIGRwbHlyOjpzbGljZSgxOjMpDQpgYGANCg0KDQojIyMgMTUuMS4xIEZsdW94ZXRpbmUgDQoNCmBgYHtyfQ0Kc3BwX29yZGVyIDwtIFBJQ09fZGYgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKGNvbXBvdW5kX25hbWUgPT0gIkZsdW94ZXRpbmUiKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzcGVjaWVzX25hbWUpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IG4oKSkgJT4lIA0KICBkcGx5cjo6YXJyYW5nZShkZXNjKG4pKSAlPiUgDQogIGRwbHlyOjpzbGljZSgxOjUpICU+JSANCiAgcHVsbChzcGVjaWVzX25hbWUpDQoNCmJlaF9vcmRlciA8LSBQSUNPX2RmICU+JSANCiAgZHBseXI6OmZpbHRlcihjb21wb3VuZF9uYW1lID09ICJGbHVveGV0aW5lIiAmIHNwZWNpZXNfbmFtZSAlaW4lIHNwcF9vcmRlcikgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoYmVoYXZfY2F0KSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBuKCkpICU+JSANCiAgZHBseXI6OmFycmFuZ2UoZGVzYyhuKSkgJT4lIA0KICBwdWxsKGJlaGF2X2NhdCkNCg0KUElDT19mbHVveGV0aW5lIDwtIFBJQ09fZGYgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKGNvbXBvdW5kX25hbWUgPT0gIkZsdW94ZXRpbmUiICYgc3BlY2llc19uYW1lICVpbiUgc3BwX29yZGVyKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoDQogICAgICAgICAgICAgICAgc3BlY2llc19uYW1lID0gZmFjdG9yKHNwZWNpZXNfbmFtZSwgbGV2ZWxzID0gc3BwX29yZGVyKSwNCiAgICAgICAgICAgICAgICBiZWhhdl9jYXQgPSBmYWN0b3IoYmVoYXZfY2F0LCBsZXZlbHMgPSBiZWhfb3JkZXIpLA0KICApICU+JSANCiAgZHBseXI6OnNlbGVjdChzcGVjaWVzX25hbWUsIGJlaGF2X2NhdCkNCmBgYA0KDQoNCmBgYHtyfQ0KUElDT19mbHVveGV0aW5lICU+JSANCiAgZHBseXI6OmZpbHRlcihzcGVjaWVzX25hbWUgPT0gIkJldHRhIHNwbGVuZGVucyIpICU+JSANCiAgZHBseXI6OmRpc3RpbmN0KGJlaGF2X2NhdCkNCmBgYA0KDQoNCmBgYHtyfQ0KUElDT19mbHVveGV0aW5lX3NhbmtleSA8LSBoaWdoY2hhcnRlcjo6aGNoYXJ0KGRhdGFfdG9fc2Fua2V5KFBJQ09fZmx1b3hldGluZSksICJzYW5rZXkiLCBuYW1lID0gIlBJQ08iKQ0KUElDT19mbHVveGV0aW5lX3NhbmtleQ0KYGBgDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQ0Kc2V0d2QoZmlndXJlc19wYXRoKQ0KaHRtbHdpZGdldHM6OnNhdmVXaWRnZXQod2lkZ2V0ID0gUElDT19mbHVveGV0aW5lX3NhbmtleSwgZmlsZSA9ICJQSUNPX2ZsdW94ZXRpbmVfc2Fua2V5Lmh0bWwiKQ0KYGBgDQoNCg0KYGBge3IsIHdhcm5pbmc9RkFMU0V9DQpzZXR3ZChmaWd1cmVzX3BhdGgpDQojIE1ha2UgYSB3ZWJzaG90IGluIHBkZiA6IGhpZ2ggcXVhbGl0eSBidXQgY2FuIG5vdCBjaG9vc2UgcHJpbnRlZCB6b25lDQp3ZWJzaG90Ojp3ZWJzaG90KCJQSUNPX2ZsdW94ZXRpbmVfc2Fua2V5Lmh0bWwiICwgIlBJQ09fZmx1b3hldGluZV9zYW5rZXkucGRmIiwgZGVsYXkgPSAxMCkNCmBgYA0KDQoNCiMjIyAxNS4xLjIgRGlhemVwYW0gDQoNCmBgYHtyfQ0Kc3BwX29yZGVyIDwtIFBJQ09fZGYgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKGNvbXBvdW5kX25hbWUgPT0gIkRpYXplcGFtIikgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3BlY2llc19uYW1lKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBuKCkpICU+JSANCiAgZHBseXI6OmFycmFuZ2UoZGVzYyhuKSkgJT4lIA0KICBkcGx5cjo6c2xpY2UoMTo1KSAlPiUgDQogIHB1bGwoc3BlY2llc19uYW1lKQ0KDQpiZWhfb3JkZXIgPC0gUElDT19kZiAlPiUgDQogIGRwbHlyOjpmaWx0ZXIoY29tcG91bmRfbmFtZSA9PSAiRGlhemVwYW0iICYgc3BlY2llc19uYW1lICVpbiUgc3BwX29yZGVyKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShiZWhhdl9jYXQpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IG4oKSkgJT4lIA0KICBkcGx5cjo6YXJyYW5nZShkZXNjKG4pKSAlPiUgDQogIHB1bGwoYmVoYXZfY2F0KQ0KDQpQSUNPX2RpYXplcGFtIDwtIFBJQ09fZGYgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKGNvbXBvdW5kX25hbWUgPT0gIkRpYXplcGFtIiAmIHNwZWNpZXNfbmFtZSAlaW4lIHNwcF9vcmRlcikgJT4lIA0KICBkcGx5cjo6bXV0YXRlKA0KICAgICAgICAgICAgICAgIHNwZWNpZXNfbmFtZSA9IGZhY3RvcihzcGVjaWVzX25hbWUsIGxldmVscyA9IHNwcF9vcmRlciksDQogICAgICAgICAgICAgICAgYmVoYXZfY2F0ID0gZmFjdG9yKGJlaGF2X2NhdCwgbGV2ZWxzID0gYmVoX29yZGVyKSwNCiAgKSAlPiUgDQogIGRwbHlyOjpzZWxlY3Qoc3BlY2llc19uYW1lLCBiZWhhdl9jYXQpDQpgYGANCg0KDQpgYGB7cn0NClBJQ09fZGlhemVwYW1fc2Fua2V5IDwtIGhpZ2hjaGFydGVyOjpoY2hhcnQoZGF0YV90b19zYW5rZXkoUElDT19kaWF6ZXBhbSksICJzYW5rZXkiLCBuYW1lID0gIlBJQ08iKQ0KUElDT19kaWF6ZXBhbV9zYW5rZXkNCmBgYA0KDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQ0Kc2V0d2QoZmlndXJlc19wYXRoKQ0KaHRtbHdpZGdldHM6OnNhdmVXaWRnZXQod2lkZ2V0ID0gUElDT19kaWF6ZXBhbV9zYW5rZXksIGZpbGUgPSAiUElDT19kaWF6ZXBhbV9zYW5rZXkuaHRtbCIpDQpgYGANCg0KDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCnNldHdkKGZpZ3VyZXNfcGF0aCkNCiMgTWFrZSBhIHdlYnNob3QgaW4gcGRmIDogaGlnaCBxdWFsaXR5IGJ1dCBjYW4gbm90IGNob29zZSBwcmludGVkIHpvbmUNCndlYnNob3Q6OndlYnNob3QoIlBJQ09fZGlhemVwYW1fc2Fua2V5Lmh0bWwiICwgIlBJQ09fZGlhemVwYW1fc2Fua2V5LnBkZiIsIGRlbGF5ID0gMTApDQpgYGANCg0KDQojIyMgMTUuMy4xIDE3LWFscGhhLWV0aGlueWxlc3RyYWRpb2wgDQoNCmBgYHtyfQ0Kc3BwX29yZGVyIDwtIFBJQ09fZGYgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKGNvbXBvdW5kX25hbWUgPT0gIjE3LWFscGhhLWV0aGlueWxlc3RyYWRpb2wiKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzcGVjaWVzX25hbWUpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IG4oKSkgJT4lIA0KICBkcGx5cjo6YXJyYW5nZShkZXNjKG4pKSAlPiUgDQogIGRwbHlyOjpzbGljZSgxOjUpICU+JSANCiAgcHVsbChzcGVjaWVzX25hbWUpDQoNCmJlaF9vcmRlciA8LSBQSUNPX2RmICU+JSANCiAgZHBseXI6OmZpbHRlcihjb21wb3VuZF9uYW1lID09ICIxNy1hbHBoYS1ldGhpbnlsZXN0cmFkaW9sIiAmIHNwZWNpZXNfbmFtZSAlaW4lIHNwcF9vcmRlcikgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoYmVoYXZfY2F0KSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBuKCkpICU+JSANCiAgZHBseXI6OmFycmFuZ2UoZGVzYyhuKSkgJT4lIA0KICBwdWxsKGJlaGF2X2NhdCkNCg0KUElDT19FRTIgPC0gUElDT19kZiAlPiUgDQogIGRwbHlyOjpmaWx0ZXIoY29tcG91bmRfbmFtZSA9PSAiMTctYWxwaGEtZXRoaW55bGVzdHJhZGlvbCIgJiBzcGVjaWVzX25hbWUgJWluJSBzcHBfb3JkZXIpICU+JSANCiAgZHBseXI6Om11dGF0ZSgNCiAgICAgICAgICAgICAgICBzcGVjaWVzX25hbWUgPSBmYWN0b3Ioc3BlY2llc19uYW1lLCBsZXZlbHMgPSBzcHBfb3JkZXIpLA0KICAgICAgICAgICAgICAgIGJlaGF2X2NhdCA9IGZhY3RvcihiZWhhdl9jYXQsIGxldmVscyA9IGJlaF9vcmRlciksDQogICkgJT4lIA0KICBkcGx5cjo6c2VsZWN0KHNwZWNpZXNfbmFtZSwgYmVoYXZfY2F0KQ0KYGBgDQoNCg0KYGBge3J9DQpQSUNPX0VFMl9zYW5rZXkgPC0gaGlnaGNoYXJ0ZXI6OmhjaGFydChkYXRhX3RvX3NhbmtleShQSUNPX0VFMiksICJzYW5rZXkiLCBuYW1lID0gIlBJQ08iKQ0KUElDT19FRTJfc2Fua2V5DQpgYGANCg0KDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCnNldHdkKGZpZ3VyZXNfcGF0aCkNCmh0bWx3aWRnZXRzOjpzYXZlV2lkZ2V0KHdpZGdldCA9IFBJQ09fRUUyX3NhbmtleSwgZmlsZSA9ICJQSUNPX0VFMl9zYW5rZXkuaHRtbCIpDQpgYGANCg0KDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCnNldHdkKGZpZ3VyZXNfcGF0aCkNCiMgTWFrZSBhIHdlYnNob3QgaW4gcGRmIDogaGlnaCBxdWFsaXR5IGJ1dCBjYW4gbm90IGNob29zZSBwcmludGVkIHpvbmUNCndlYnNob3Q6OndlYnNob3QoIlBJQ09fRUUyX3NhbmtleS5odG1sIiAsICJQSUNPX0VFMl9zYW5rZXkucGRmIiwgZGVsYXkgPSAxMCkNCmBgYA0KDQojIDE2IEtub3dsZWRnZSBjbHVzdGVycyBhbmQgZ2Fwcw0KDQpJZGVudGlmeSBrbm93bGVkZ2UgY2x1c3RlcnMgYW5kIGdhcHMuDQoNCldlIHdpbGwgYWxzbyBkbyB0aGlzIGJ5IHN0dWR5IG1vdGl2YXRpb24sIGJlY2F1c2UgdGhlIGtub3dsZWFnZSBnYXBzIHdpbGwgYmUgbW90aXZhdGlvbiBzcGVzZmljLiANCg0KIyMgMTYuMSBTcGVjaWVzIGNsYXNzDQoNCkZpcnN0IGxvb2sgYnkgc3BlY2llcyBjbGFzcw0KDQpNYWtpbmcgYSBkYXRhZnJhbWUNCg0KYGBge3J9DQpiZWhhdl9jYXRfY2xhc3NfbG9uZyA8LSBQSUNPX2RmICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHN0dWR5X21vdGl2YXRpb24sIHNwZWNpZXNfY2xhc3MsIGJlaGF2X2NhdCkgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShjb3VudCA9IG4oKSkgJT4lIA0KICB0aWR5cjo6Y29tcGxldGUoc3R1ZHlfbW90aXZhdGlvbiwgc3BlY2llc19jbGFzcywgYmVoYXZfY2F0LCBmaWxsID0gbGlzdChjb3VudCA9IDApKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uLCBzcGVjaWVzX2NsYXNzKSAlPiUgDQogIGRwbHlyOjptdXRhdGUodG90YWxfY2xhc3NfbW90aXZhdGlvbiA9IHN1bShjb3VudCkpICU+JSANCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjptdXRhdGUocmVsX3BlcmNlbnQgPSByb3VuZChjb3VudC90b3RhbF9jbGFzc19tb3RpdmF0aW9uKjEwMCwwKSwNCiAgICAgICAgICAgICAgICByZWxfcGVyY2VudCA9IGlmX2Vsc2UoaXMuZmluaXRlKHJlbF9wZXJjZW50KSwgcmVsX3BlcmNlbnQsIDApDQogICkNCg0KY2xhc3Nfb3JkZXIgPC0gYmVoYXZfY2F0X2NsYXNzX2xvbmcgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3BlY2llc19jbGFzcykgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gc3VtKGNvdW50KSkgJT4lIA0KICBkcGx5cjo6YXJyYW5nZShuKSAlPiUgDQogIGRwbHlyOjpwdWxsKHNwZWNpZXNfY2xhc3MpDQoNCmJlaGF2X2NhdF9vcmRlciA8LSBiZWhhdl9jYXRfY2xhc3NfbG9uZyAlPiUgDQogIGRwbHlyOjpncm91cF9ieShiZWhhdl9jYXQpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IHN1bShjb3VudCkpICU+JSANCiAgZHBseXI6OmFycmFuZ2UoZGVzYyhuKSkgJT4lIA0KICBkcGx5cjo6cHVsbChiZWhhdl9jYXQpDQoNCmJlaGF2X2NhdF9jbGFzc19sb25nIDwtIGJlaGF2X2NhdF9jbGFzc19sb25nICU+JSANCiAgZHBseXI6Om11dGF0ZShzcGVjaWVzX2NsYXNzID0gZmFjdG9yKHNwZWNpZXNfY2xhc3MsIGxldmVscyA9IGNsYXNzX29yZGVyKSwNCiAgICAgICAgICAgICAgICBiZWhhdl9jYXQgPSBmYWN0b3IoYmVoYXZfY2F0LCBsZXZlbHMgPSBiZWhhdl9jYXRfb3JkZXIpDQogICAgICAgICAgICAgICAgKQ0KYGBgDQoNCmBgYHtyfQ0KY3VzdF9jb2wgPC0gY29sb3JSYW1wUGFsZXR0ZShjKCIjRkRFREY0IiwgIiNGMDY4QTciKSkoMzApDQoNCmJlaGF2X2NsYXNzX2htIDwtIGJlaGF2X2NhdF9jbGFzc19sb25nICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gYmVoYXZfY2F0LCB5ID0gc3BlY2llc19jbGFzcywgZmlsbCA9IGNvdW50KSkgKw0KICBnZW9tX3RpbGUoKSArDQogIHNjYWxlX2ZpbGxfZ3JhZGllbnRuKGNvbG9ycyA9IGN1c3RfY29sLCBuYS52YWx1ZSA9ICJ3aGl0ZSIsIGxpbWl0cyA9IGMoMSwgbWF4KGJlaGF2X2NhdF9jbGFzc19sb25nJGNvdW50LCBuYS5ybSA9IFRSVUUpKSwgZ3VpZGUgPSAibm9uZSIpICsNCiAgdGhlbWVfYncoKSArDQogIGZhY2V0X3dyYXAofnN0dWR5X21vdGl2YXRpb24pICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkgKw0KICBsYWJzKA0KICAgIHggPSAiQmVoYXZpb3VyIiwNCiAgICB5ID0gIlNwZWNpZXMgQ2xhc3MiLA0KICAgIGZpbGwgPSAiQ291bnQiDQogICkNCmJlaGF2X2NsYXNzX2htDQpgYGANCg0KDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCnNldHdkKGZpZ3VyZXNfcGF0aCkNCmdnc2F2ZSgiYmVoYXZfY2xhc3NfaG0ucGRmIiwgcGxvdCA9IGJlaGF2X2NsYXNzX2htLCB3aWR0aCA9IDguMywgaGVpZ2h0ID0gMTEuNy8yKQ0KYGBgDQoNCg0KVGhpcyBvbmUgdXNlcyByZWxhdGl2ZSB2YXVsZXMgZm9yIGVhY2ggY2xhc3MgKGUuZy4gcm93IGluIHRoZSBoZWF0IG1hcCkNCg0KYGBge3J9DQpjdXN0X2NvbCA8LSBjb2xvclJhbXBQYWxldHRlKGJyZXdlci5wYWwoNCwgIk9yYW5nZXMiKSkoMzApDQoNCmJlaGF2X2NsYXNzX3JlbF9obSA8LSBiZWhhdl9jYXRfY2xhc3NfbG9uZyAlPiUgDQogIGdncGxvdChhZXMoeCA9IGJlaGF2X2NhdCwgeSA9IHNwZWNpZXNfY2xhc3MsIGZpbGwgPSByZWxfcGVyY2VudCkpICsNCiAgZ2VvbV90aWxlKCkgKw0KICNnZW9tX3RleHQoYWVzKGxhYmVsID0gaWZlbHNlKHJlbF9wZXJjZW50ID09IDAsIE5BLCByZWxfcGVyY2VudCkpLCBjb2xvciA9ICJibGFjayIsIHNpemUgPSAzKSArDQogIHNjYWxlX2ZpbGxfZ3JhZGllbnRuKGNvbG9ycyA9IGN1c3RfY29sLCBuYS52YWx1ZSA9ICJ3aGl0ZSIsIGxpbWl0cyA9IGMoMSwgbWF4KGJlaGF2X2NhdF9jbGFzc19sb25nJGNvdW50LCBuYS5ybSA9IFRSVUUpKSwgZ3VpZGUgPSAibm9uZSIpICsNCiAgdGhlbWVfYncoKSArDQogIGZhY2V0X3dyYXAofnN0dWR5X21vdGl2YXRpb24pICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkgKw0KICBsYWJzKA0KICAgIHggPSAiQmVoYXZpb3VyIiwNCiAgICB5ID0gIlNwZWNpZXMgQ2xhc3MiLA0KICAgIGZpbGwgPSAiQ291bnQiDQogICkNCmJlaGF2X2NsYXNzX3JlbF9obQ0KYGBgDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQ0Kc2V0d2QoZmlndXJlc19wYXRoKQ0KZ2dzYXZlKCJiZWhhdl9jbGFzc19yZWxfaG0ucGRmIiwgcGxvdCA9IGJlaGF2X2NsYXNzX3JlbF9obSwgd2lkdGggPSA4LjMsIGhlaWdodCA9IDExLjcvMikNCmBgYA0KDQoNCiMjIDE2LjIgQ29tcG91bmQgY2x1c3Rlci9nYXBzDQoNCk5vdyBsb29raW5nIGJ5IGNvbXBvdW5kDQoNCk1ha2luZyBhIGRhdGFmcmFtZQ0KDQpgYGB7cn0NCmJlaGF2X2F0Y19sb25nIDwtIFBJQ09fZGYgJT4lIA0KICBzZXBhcmF0ZV9yb3dzKGNvbXBvdW5kX2F0Y19sZXZlbF8zLCBzZXAgPSAiOyIpICU+JQ0KICBkcGx5cjo6Z3JvdXBfYnkoc3R1ZHlfbW90aXZhdGlvbiwgY29tcG91bmRfYXRjX2xldmVsXzMsIGJlaGF2X2NhdCkgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShjb3VudCA9IG4oKSkgJT4lIA0KICB0aWR5cjo6Y29tcGxldGUoc3R1ZHlfbW90aXZhdGlvbiwgY29tcG91bmRfYXRjX2xldmVsXzMsIGJlaGF2X2NhdCwgZmlsbCA9IGxpc3QoY291bnQgPSAwKSkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3R1ZHlfbW90aXZhdGlvbiwgY29tcG91bmRfYXRjX2xldmVsXzMpICU+JSANCiAgZHBseXI6Om11dGF0ZSh0b3RhbF9hdGNfbW90aXZhdGlvbiA9IHN1bShjb3VudCkpICU+JSANCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjptdXRhdGUocmVsX3BlcmNlbnQgPSByb3VuZChjb3VudC90b3RhbF9hdGNfbW90aXZhdGlvbioxMDAsMCksDQogICAgICAgICAgICAgICAgcmVsX3BlcmNlbnQgPSBpZl9lbHNlKGlzLmZpbml0ZShyZWxfcGVyY2VudCksIHJlbF9wZXJjZW50LCAwKQ0KICApDQoNCmF0Y19vcmRlciA8LSBiZWhhdl9hdGNfbG9uZyAlPiUgDQogIGRwbHlyOjpncm91cF9ieShjb21wb3VuZF9hdGNfbGV2ZWxfMykgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gc3VtKGNvdW50KSkgJT4lIA0KICBkcGx5cjo6YXJyYW5nZShuKSAlPiUgDQogIGRwbHlyOjpwdWxsKGNvbXBvdW5kX2F0Y19sZXZlbF8zKQ0KDQpiZWhhdl9jYXRfb3JkZXIgPC0gYmVoYXZfYXRjX2xvbmcgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoYmVoYXZfY2F0KSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBzdW0oY291bnQpKSAlPiUgDQogIGRwbHlyOjphcnJhbmdlKGRlc2MobikpICU+JSANCiAgZHBseXI6OnB1bGwoYmVoYXZfY2F0KQ0KDQpiZWhhdl9hdGNfbG9uZyA8LSBiZWhhdl9hdGNfbG9uZyAlPiUgDQogIGRwbHlyOjptdXRhdGUoY29tcG91bmRfYXRjX2xldmVsXzMgPSBmYWN0b3IoY29tcG91bmRfYXRjX2xldmVsXzMsIGxldmVscyA9IGF0Y19vcmRlciksDQogICAgICAgICAgICAgICAgYmVoYXZfY2F0ID0gZmFjdG9yKGJlaGF2X2NhdCwgbGV2ZWxzID0gYmVoYXZfY2F0X29yZGVyKQ0KICAgICAgICAgICAgICAgICkNCmBgYA0KDQpUaGVyZSBhcmUgMTMyIEFUQyBsZXZlbCAzIGNvZGVzLiBTbyB0aGUgcGxvdCBiZWxvdyBpcyBub3QgZ29pbmcgdG8gYmUgdmVyeSBpbmZvcm1hdGl2ZS4gSXQgY291bGQgYmUgdXNlZnVsIGlmIHlvdSBhcmUgb25seSBpbnRlcmVzdGVkIGluIGEgZmV3IEFUQyBncm91cHMuIA0KDQpgYGB7cn0NCmJlaGF2X2F0Y19sb25nICU+JSANCiAgZHBseXI6OmRpc3RpbmN0KGNvbXBvdW5kX2F0Y19sZXZlbF8zKSAlPiUgDQogIG5yb3coKQ0KYGBgDQoNCg0KDQpgYGB7cn0NCmN1c3RfY29sIDwtIGNvbG9yUmFtcFBhbGV0dGUoYygiI0ZERURGNCIsICIjRjA2OEE3IikpKDMwKQ0KDQpiZWhhdl9hdGNfaG0gPC0gYmVoYXZfYXRjX2xvbmcgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSBiZWhhdl9jYXQsIHkgPSBjb21wb3VuZF9hdGNfbGV2ZWxfMywgZmlsbCA9IGNvdW50KSkgKw0KICBnZW9tX3RpbGUoKSArDQogICNnZW9tX3RleHQoYWVzKGxhYmVsID0gaWZlbHNlKGNvdW50ID09IDAsIE5BLCBjb3VudCkpLCBjb2xvciA9ICJibGFjayIsIHNpemUgPSAzKSArDQogIHNjYWxlX2ZpbGxfZ3JhZGllbnRuKGNvbG9ycyA9IGN1c3RfY29sLCBuYS52YWx1ZSA9ICJ3aGl0ZSIsIGxpbWl0cyA9IGMoMSwgbWF4KGJlaGF2X2F0Y19sb25nJGNvdW50LCBuYS5ybSA9IFRSVUUpKSwgZ3VpZGUgPSAibm9uZSIpICsNCiAgdGhlbWVfdm9pZCgpICsNCiAgZmFjZXRfd3JhcCh+c3R1ZHlfbW90aXZhdGlvbikgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKSArDQogIGxhYnMoDQogICAgeCA9ICJCZWhhdmlvdXIiLA0KICAgIHkgPSAiU3BlY2llcyBDbGFzcyIsDQogICAgZmlsbCA9ICJDb3VudCINCiAgKQ0KYmVoYXZfYXRjX2htDQpgYGANCg0KDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCnNldHdkKGZpZ3VyZXNfcGF0aCkNCmdnc2F2ZSgiYmVoYXZfYXRjX2htLnBkZiIsIHBsb3QgPSBiZWhhdl9hdGNfaG0sIHdpZHRoID0gOC4zLCBoZWlnaHQgPSAxMS43LzIpDQpgYGANCg0KDQojIDE3IEFkZGl0aW9uYWwgYmlvbWFya2Vycw0KDQpgYGB7cn0NCkVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShhcnRpY2xlX2lkKSAlPiUgDQogIGRwbHlyOjpzYW1wbGVfbigxKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShhZGRpdGlvbmFsX2Jpb21hcmtlcnMpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IG4oKSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHRvdGFsID0gc3VtKG4pLA0KICAgICAgICAgICAgICAgIHBlcmNlbnQgPSBuL3RvdGFsKQ0KYGBgDQoNCg0KYGBge3J9DQpFSVBBQUJfZGF0YWJhc2UgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoYXJ0aWNsZV9pZCkgJT4lIA0KICBkcGx5cjo6c2FtcGxlX24oMSkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkodmFsaWRpdHlfc3Vydml2YWxfZ3Jvd3RoX3JlcHJvZHVjdGlvbikgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gbigpKSAlPiUgDQogIGRwbHlyOjptdXRhdGUodG90YWwgPSBzdW0obiksDQogICAgICAgICAgICAgICAgcGVyY2VudCA9IG4vdG90YWwpDQpgYGANCg0KIyAxOCBWYWxpZGl0eQ0KDQoNClRoaXMgYSBsaXN0IG9mIGFsbCAxOSBtZXRhZGF0YSB0aGF0IHJlbGF0ZSB0byBvdXIgdmFsaWRpdHkgaW5mb3JtYXRpb24uDQoNCmMoInZhbGlkaXR5X2d1aWRlbGluZSIsICJ2YWxpZGl0eV9nb29kX2xhYm9yYXRvcnlfcHJhY3RpY2UiLCAidmFsaWRpdHlfc3Vydml2YWxfZ3Jvd3RoX3JlcHJvZHVjdGlvbiIsICJ2YWxpZGl0eV9hbmltYWxfZmVlZGluZyIsICJ2YWxpZGl0eV93YXRlcl9xdWFsaXR5IiwgInZhbGlkaXR5X2xpZ2h0X2N5Y2xlIiwgInZhbGlkaXR5X3JhbmRvbWl6YXRpb24iLCAidmFsaWRpdHlfYmVoYXZfc2NvcmluZ19tZXRob2QiLCAidmFsaWRpdHlfYmVoYXZfYmxpbmRpbmciLCAidmFsaWRpdHlfY29uZmxpY3Rfc3RhdGVtZW50IiwgInNwZWNpZXNfc291cmNlIiwgInNwZWNpZXNfc3RhZ2UiLCAic3BlY2llc19zZXgiLCAiY29tcG91bmRfbWluX2R1cmF0aW9uX2V4cG9zdXJlIiwgImNvbXBvdW5kX21heF9kdXJhdGlvbl9leHBvc3VyZSIsICJ2YWxpZGl0eV9jb21wb3VuZF9jYXNfcmVwb3J0ZWQiLCAidmFsaWRpdHlfY29tcG91bmRfcHVyaXR5X3JlcG9ydGVkIiwgInZhbGlkaXR5X2NvbXBvdW5kX3dhdGVyX3ZlcmlmaWNhdGlvbiIsICJ2YWxpZGl0eV9jb21wb3VuZF9hbmltYWxfdmVyaWZpY2F0aW9uIikNCg0KIyMgMTguMSBEaWQgaXQgZm9sbG93IGEgZ3VpZGVsaW5lIChDUkVEIFExKQ0KDQpgYGB7cn0NCmd1aWRlbGluZSA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lDQogIGRwbHlyOjpncm91cF9ieShhcnRpY2xlX2lkKSAlPiUgDQogIGRwbHlyOjpzYW1wbGVfbigxKSAlPiUgDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkodmFsaWRpdHlfZ3VpZGVsaW5lLCBzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBuKCkpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHN0dWR5X21vdGl2YXRpb24pICU+JSANCiAgZHBseXI6Om11dGF0ZSh0b3RhbF9tb3RpdmF0aW9uID0gc3VtKG4pKSAlPiUgDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHBlcmNlbnQgPSByb3VuZChuL3RvdGFsX21vdGl2YXRpb24qMTAwLDEpKSAlPiUgDQogIGRwbHlyOjpzZWxlY3QoLXRvdGFsX21vdGl2YXRpb24pDQoNCmd1aWRlbGluZV9hbGwgPC0gIGd1aWRlbGluZSAlPiUgDQogIGRwbHlyOjpncm91cF9ieSh2YWxpZGl0eV9ndWlkZWxpbmUpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IHN1bShuKSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHN0dWR5X21vdGl2YXRpb24gPSAiT3ZlcmFsbCIsDQogICAgICAgICAgICAgICAgcGVyY2VudCA9IHJvdW5kKG4vc3VtKG4pKjEwMCwxKSkNCiAgDQoNCmd1aWRlbGluZV9hbGwgPC0gcmJpbmQoZ3VpZGVsaW5lX2FsbCwgZ3VpZGVsaW5lKSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIodmFsaWRpdHlfZ3VpZGVsaW5lID09ICJZZXMiKQ0KZ3VpZGVsaW5lX2FsbA0KYGBgDQoNCg0KIyMgMTguMiBEaWQgaXQgdXNlIGdvb2QgbGFib3JhdG9yeSBwcmFjdGljZSAoQ1JFRCBRMikNCg0KYGBge3J9DQpHTFAgPC0gRUlQQUFCX2RhdGFiYXNlICU+JQ0KICBkcGx5cjo6Z3JvdXBfYnkoYXJ0aWNsZV9pZCkgJT4lIA0KICBkcGx5cjo6c2FtcGxlX24oMSkgJT4lIA0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHZhbGlkaXR5X2dvb2RfbGFib3JhdG9yeV9wcmFjdGljZSwgc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gbigpKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIGRwbHlyOjptdXRhdGUodG90YWxfbW90aXZhdGlvbiA9IHN1bShuKSkgJT4lIA0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6Om11dGF0ZShwZXJjZW50ID0gcm91bmQobi90b3RhbF9tb3RpdmF0aW9uKjEwMCwxKSkgJT4lIA0KICBkcGx5cjo6c2VsZWN0KC10b3RhbF9tb3RpdmF0aW9uKQ0KDQpHTFBfYWxsIDwtICBHTFAgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkodmFsaWRpdHlfZ29vZF9sYWJvcmF0b3J5X3ByYWN0aWNlKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBzdW0obikpICU+JSANCiAgZHBseXI6Om11dGF0ZShzdHVkeV9tb3RpdmF0aW9uID0gIk92ZXJhbGwiLA0KICAgICAgICAgICAgICAgIHBlcmNlbnQgPSByb3VuZChuL3N1bShuKSoxMDAsMSkpIA0KICANCg0KR0xQX2FsbCA8LSByYmluZChHTFBfYWxsLCBHTFApICU+JSANCiAgZHBseXI6OmZpbHRlcih2YWxpZGl0eV9nb29kX2xhYm9yYXRvcnlfcHJhY3RpY2UgPT0gIlllcyIpDQpHTFBfYWxsDQpgYGANCg0KDQojIyAxOC4zIERpZCBpdCByZXBvcnQgc3Vydml2YWwsIGdyb3d0aCBhbmQvb3IgcmVwcm9kdWN0aW9uIChDUkVEIFEzKQ0KDQoNCmBgYHtyfQ0Kc3Vydml2YWxfZ3Jvd3RoX3JlcHJvZHVjdGlvbiA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lDQogIGRwbHlyOjpncm91cF9ieShhcnRpY2xlX2lkKSAlPiUgDQogIGRwbHlyOjpzYW1wbGVfbigxKSAlPiUgDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkodmFsaWRpdHlfc3Vydml2YWxfZ3Jvd3RoX3JlcHJvZHVjdGlvbiwgc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gbigpKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIGRwbHlyOjptdXRhdGUodG90YWxfbW90aXZhdGlvbiA9IHN1bShuKSkgJT4lIA0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6Om11dGF0ZShwZXJjZW50ID0gcm91bmQobi90b3RhbF9tb3RpdmF0aW9uKjEwMCwxKSkgJT4lIA0KICBkcGx5cjo6c2VsZWN0KC10b3RhbF9tb3RpdmF0aW9uKQ0KDQpzdXJ2aXZhbF9ncm93dGhfcmVwcm9kdWN0aW9uX2FsbCA8LSAgc3Vydml2YWxfZ3Jvd3RoX3JlcHJvZHVjdGlvbiAlPiUgDQogIGRwbHlyOjpncm91cF9ieSh2YWxpZGl0eV9zdXJ2aXZhbF9ncm93dGhfcmVwcm9kdWN0aW9uKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBzdW0obikpICU+JSANCiAgZHBseXI6Om11dGF0ZShzdHVkeV9tb3RpdmF0aW9uID0gIk92ZXJhbGwiLA0KICAgICAgICAgICAgICAgIHBlcmNlbnQgPSByb3VuZChuL3N1bShuKSoxMDAsMSkpDQogIA0KDQpzdXJ2aXZhbF9ncm93dGhfcmVwcm9kdWN0aW9uX2FsbCA8LSByYmluZChzdXJ2aXZhbF9ncm93dGhfcmVwcm9kdWN0aW9uX2FsbCwgc3Vydml2YWxfZ3Jvd3RoX3JlcHJvZHVjdGlvbikgICU+JSANCiAgZHBseXI6OmZpbHRlcih2YWxpZGl0eV9zdXJ2aXZhbF9ncm93dGhfcmVwcm9kdWN0aW9uID09ICJZZXMiKQ0Kc3Vydml2YWxfZ3Jvd3RoX3JlcHJvZHVjdGlvbl9hbGwNCmBgYA0KDQoNCiMjIDE4LjQgRGlkIGl0IHJlcG9ydCBjb21wb3VuZCBjYXMgKENSRUQgUTUpDQoNCmBgYHtyfQ0KQ0FTIDwtIEVJUEFBQl9kYXRhYmFzZSAlPiUNCiAgZHBseXI6Omdyb3VwX2J5KGFydGljbGVfaWQpICU+JSANCiAgZHBseXI6OnNhbXBsZV9uKDEpICU+JSANCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieSh2YWxpZGl0eV9jb21wb3VuZF9jYXNfcmVwb3J0ZWQsIHN0dWR5X21vdGl2YXRpb24pICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IG4oKSkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHRvdGFsX21vdGl2YXRpb24gPSBzdW0obikpICU+JSANCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjptdXRhdGUocGVyY2VudCA9IHJvdW5kKG4vdG90YWxfbW90aXZhdGlvbioxMDAsMSkpICU+JSANCiAgZHBseXI6OnNlbGVjdCgtdG90YWxfbW90aXZhdGlvbikNCg0KQ0FTX2FsbCA8LSAgQ0FTICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHZhbGlkaXR5X2NvbXBvdW5kX2Nhc19yZXBvcnRlZCkgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gc3VtKG4pKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoc3R1ZHlfbW90aXZhdGlvbiA9ICJPdmVyYWxsIiwNCiAgICAgICAgICAgICAgICBwZXJjZW50ID0gcm91bmQobi9zdW0obikqMTAwLDEpKQ0KICANCg0KQ0FTX2FsbCA8LSByYmluZChDQVNfYWxsLCBDQVMpICAlPiUgDQogIGRwbHlyOjpmaWx0ZXIodmFsaWRpdHlfY29tcG91bmRfY2FzX3JlcG9ydGVkID09ICJZZXMiKQ0KQ0FTX2FsbA0KYGBgDQoNCiMjIDE4LjUgRGlkIGl0IHJlcG9ydCBjb21wb3VuZCBwdXJpdHkgKENSRUQgUTYpDQoNCmBgYHtyfQ0KcHVyaXR5IDwtIEVJUEFBQl9kYXRhYmFzZSAlPiUNCiAgZHBseXI6Omdyb3VwX2J5KGFydGljbGVfaWQpICU+JSANCiAgZHBseXI6OnNhbXBsZV9uKDEpICU+JSANCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieSh2YWxpZGl0eV9jb21wb3VuZF9wdXJpdHlfcmVwb3J0ZWQsIHN0dWR5X21vdGl2YXRpb24pICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IG4oKSkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHRvdGFsX21vdGl2YXRpb24gPSBzdW0obikpICU+JSANCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjptdXRhdGUocGVyY2VudCA9IHJvdW5kKG4vdG90YWxfbW90aXZhdGlvbioxMDAsMSkpICU+JSANCiAgZHBseXI6OnNlbGVjdCgtdG90YWxfbW90aXZhdGlvbikNCg0KcHVyaXR5X2FsbCA8LSAgcHVyaXR5ICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHZhbGlkaXR5X2NvbXBvdW5kX3B1cml0eV9yZXBvcnRlZCkgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gc3VtKG4pKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoc3R1ZHlfbW90aXZhdGlvbiA9ICJPdmVyYWxsIiwNCiAgICAgICAgICAgICAgICBwZXJjZW50ID0gcm91bmQobi9zdW0obikqMTAwLDEpKSANCiAgDQoNCnB1cml0eV9hbGwgPC0gcmJpbmQocHVyaXR5X2FsbCwgcHVyaXR5KSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIodmFsaWRpdHlfY29tcG91bmRfcHVyaXR5X3JlcG9ydGVkID09ICJZZXMiKQ0KcHVyaXR5X2FsbA0KYGBgDQoNCiMjIDE4LjYgU3BlY2llcyBpbmZvbWFydGlvbiAgKENSRUQgUTgpDQoNCiMjIyAxOC42LjEgTGlmZSBzdGFnZQ0KDQpgYGB7cn0NCnN0YWdlIDwtIEVJUEFBQl9kYXRhYmFzZSAlPiUNCiAgZHBseXI6Omdyb3VwX2J5KHVuaXF1ZV9wb3B1bGF0aW9uX2lkKSAlPiUgDQogIGRwbHlyOjpzYW1wbGVfbigxKSAlPiUgDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3BlY2llc19zdGFnZSwgc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gbigpKSAlPiUgDQogIHRpZHlyOjpzZXBhcmF0ZV9yb3dzKHNwZWNpZXNfc3RhZ2UsIHNlcCA9ICI7IikgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3BlY2llc19zdGFnZSwgc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gc3VtKG4pKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIGRwbHlyOjptdXRhdGUodG90YWxfbW90aXZhdGlvbiA9IHN1bShuKSkgJT4lIA0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6Om11dGF0ZShwZXJjZW50ID0gcm91bmQobi90b3RhbF9tb3RpdmF0aW9uKjEwMCwxKSkgJT4lIA0KICBkcGx5cjo6c2VsZWN0KC10b3RhbF9tb3RpdmF0aW9uKQ0KDQpzdGFnZV9hbGwgPC0gIHN0YWdlICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHNwZWNpZXNfc3RhZ2UpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IHN1bShuKSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHN0dWR5X21vdGl2YXRpb24gPSAiT3ZlcmFsbCIsDQogICAgICAgICAgICAgICAgcGVyY2VudCA9IHJvdW5kKG4vc3VtKG4pKjEwMCwxKSkNCiAgDQoNCnN0YWdlX2FsbCA8LSByYmluZChzdGFnZV9hbGwsIHN0YWdlKSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIoc3BlY2llc19zdGFnZSA9PSAiVW5rbm93biBvciBub3Qgc3BlY2lmaWVkIikgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHBlcmNlbnRfcmVwb3J0ZWQgPSAxMDAtcGVyY2VudCkNCnN0YWdlX2FsbA0KYGBgDQoNCiMjIyAxOC42LjEgU2V4DQoNCmBgYHtyfQ0Kc2V4IDwtIEVJUEFBQl9kYXRhYmFzZSAlPiUNCiAgZHBseXI6Omdyb3VwX2J5KHVuaXF1ZV9wb3B1bGF0aW9uX2lkKSAlPiUgDQogIGRwbHlyOjpzYW1wbGVfbigxKSAlPiUgDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3BlY2llc19zZXgsIHN0dWR5X21vdGl2YXRpb24pICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IG4oKSkgJT4lIA0KICB0aWR5cjo6c2VwYXJhdGVfcm93cyhzcGVjaWVzX3NleCwgc2VwID0gIjsiKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzcGVjaWVzX3NleCwgc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gc3VtKG4pKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIGRwbHlyOjptdXRhdGUodG90YWxfbW90aXZhdGlvbiA9IHN1bShuKSkgJT4lIA0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6Om11dGF0ZShwZXJjZW50ID0gcm91bmQobi90b3RhbF9tb3RpdmF0aW9uKjEwMCwxKSkgJT4lIA0KICBkcGx5cjo6c2VsZWN0KC10b3RhbF9tb3RpdmF0aW9uKQ0KDQpzZXhfYWxsIDwtICBzZXggJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3BlY2llc19zZXgpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IHN1bShuKSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHN0dWR5X21vdGl2YXRpb24gPSAiT3ZlcmFsbCIsDQogICAgICAgICAgICAgICAgcGVyY2VudCA9IHJvdW5kKG4vc3VtKG4pKjEwMCwxKSkNCiAgDQoNCnNleF9hbGwgPC0gcmJpbmQoc2V4X2FsbCwgc2V4KSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIoc3BlY2llc19zZXggPT0gIlVua25vd24gb3Igbm90IHNwZWNpZmllZCIpICU+JSANCiAgZHBseXI6Om11dGF0ZShwZXJjZW50X3JlcG9ydGVkID0gMTAwLXBlcmNlbnQpDQpzZXhfYWxsDQpgYGANCg0KIyMgMTguNyBUaGUgc29ydWNlIG9mIHNwZWNpZXMgKENSRUQgUTkpDQoNCmBgYHtyfQ0Kc291cmNlIDwtIEVJUEFBQl9kYXRhYmFzZSAlPiUNCiAgZHBseXI6Omdyb3VwX2J5KHVuaXF1ZV9wb3B1bGF0aW9uX2lkKSAlPiUgDQogIGRwbHlyOjpzYW1wbGVfbigxKSAlPiUgDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3BlY2llc19zb3VyY2UsIHN0dWR5X21vdGl2YXRpb24pICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IG4oKSkgJT4lIA0KICB0aWR5cjo6c2VwYXJhdGVfcm93cyhzcGVjaWVzX3NvdXJjZSwgc2VwID0gIjsiKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzcGVjaWVzX3NvdXJjZSwgc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gc3VtKG4pKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIGRwbHlyOjptdXRhdGUodG90YWxfbW90aXZhdGlvbiA9IHN1bShuKSkgJT4lIA0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6Om11dGF0ZShwZXJjZW50ID0gcm91bmQobi90b3RhbF9tb3RpdmF0aW9uKjEwMCwxKSkgJT4lIA0KICBkcGx5cjo6c2VsZWN0KC10b3RhbF9tb3RpdmF0aW9uKQ0KDQpzb3VyY2VfYWxsIDwtICBzb3VyY2UgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3BlY2llc19zb3VyY2UpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IHN1bShuKSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHN0dWR5X21vdGl2YXRpb24gPSAiT3ZlcmFsbCIsDQogICAgICAgICAgICAgICAgcGVyY2VudCA9IHJvdW5kKG4vc3VtKG4pKjEwMCwxKSkNCiAgDQoNCnNvdXJjZV9hbGwgPC0gcmJpbmQoc291cmNlX2FsbCwgc291cmNlKSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIoc3BlY2llc19zb3VyY2UgPT0gIk5vdCByZXBvcnRlZCIpICU+JSANCiAgZHBseXI6Om11dGF0ZShwZXJjZW50X3JlcG9ydGVkID0gMTAwLXBlcmNlbnQpDQpzb3VyY2VfYWxsDQpgYGANCg0KIyMgMTguOCBleHBlcmltZW50YWwgc3lzdGVtIChDUkVEIFExMSkNCg0KIyMjIDE4LjguMSBGZWVkaW5nDQoNCg0KYGBge3J9DQpmZWVkaW5nIDwtIEVJUEFBQl9kYXRhYmFzZSAlPiUNCiAgZHBseXI6Omdyb3VwX2J5KGFydGljbGVfaWQpICU+JSANCiAgZHBseXI6OnNhbXBsZV9uKDEpICU+JSANCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieSh2YWxpZGl0eV9hbmltYWxfZmVlZGluZywgc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gbigpKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIGRwbHlyOjptdXRhdGUodG90YWxfbW90aXZhdGlvbiA9IHN1bShuKSkgJT4lIA0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6Om11dGF0ZShwZXJjZW50ID0gcm91bmQobi90b3RhbF9tb3RpdmF0aW9uKjEwMCwxKSkgJT4lIA0KICBkcGx5cjo6c2VsZWN0KC10b3RhbF9tb3RpdmF0aW9uKQ0KDQpmZWVkaW5nX2FsbCA8LSAgZmVlZGluZyAlPiUgDQogIGRwbHlyOjpncm91cF9ieSh2YWxpZGl0eV9hbmltYWxfZmVlZGluZykgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gc3VtKG4pKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoc3R1ZHlfbW90aXZhdGlvbiA9ICJPdmVyYWxsIiwNCiAgICAgICAgICAgICAgICBwZXJjZW50ID0gcm91bmQobi9zdW0obikqMTAwLDEpKSANCiAgDQoNCmZlZWRpbmdfYWxsIDwtIHJiaW5kKGZlZWRpbmdfYWxsLCBmZWVkaW5nKSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIodmFsaWRpdHlfYW5pbWFsX2ZlZWRpbmcgPT0gIlllcyIpDQpmZWVkaW5nX2FsbA0KYGBgDQoNCiMjIyAxOC44LjEgV2F0ZXIgcXVhbGl0eQ0KDQpgYGB7cn0NCndhdGVyIDwtIEVJUEFBQl9kYXRhYmFzZSAlPiUNCiAgZHBseXI6Omdyb3VwX2J5KGFydGljbGVfaWQpICU+JSANCiAgZHBseXI6OnNhbXBsZV9uKDEpICU+JSANCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieSh2YWxpZGl0eV93YXRlcl9xdWFsaXR5LCBzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBuKCkpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHN0dWR5X21vdGl2YXRpb24pICU+JSANCiAgZHBseXI6Om11dGF0ZSh0b3RhbF9tb3RpdmF0aW9uID0gc3VtKG4pKSAlPiUgDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHBlcmNlbnQgPSByb3VuZChuL3RvdGFsX21vdGl2YXRpb24qMTAwLDEpKSAlPiUgDQogIGRwbHlyOjpzZWxlY3QoLXRvdGFsX21vdGl2YXRpb24pDQoNCndhdGVyX2FsbCA8LSAgd2F0ZXIgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkodmFsaWRpdHlfd2F0ZXJfcXVhbGl0eSkgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gc3VtKG4pKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoc3R1ZHlfbW90aXZhdGlvbiA9ICJPdmVyYWxsIiwNCiAgICAgICAgICAgICAgICBwZXJjZW50ID0gcm91bmQobi9zdW0obikqMTAwLDEpKSANCiAgDQoNCndhdGVyX2FsbCA8LSByYmluZCh3YXRlcl9hbGwsIHdhdGVyKSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIodmFsaWRpdHlfd2F0ZXJfcXVhbGl0eSA9PSAiWWVzIikNCndhdGVyX2FsbA0KYGBgDQoNCiMjIyAxOC44LjEgbGlnaHQgY3ljbGUNCiANCmBgYHtyfQ0KbGlnaHQgPC0gRUlQQUFCX2RhdGFiYXNlICU+JQ0KICBkcGx5cjo6Z3JvdXBfYnkoYXJ0aWNsZV9pZCkgJT4lIA0KICBkcGx5cjo6c2FtcGxlX24oMSkgJT4lIA0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHZhbGlkaXR5X2xpZ2h0X2N5Y2xlLCBzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBuKCkpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHN0dWR5X21vdGl2YXRpb24pICU+JSANCiAgZHBseXI6Om11dGF0ZSh0b3RhbF9tb3RpdmF0aW9uID0gc3VtKG4pKSAlPiUgDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHBlcmNlbnQgPSByb3VuZChuL3RvdGFsX21vdGl2YXRpb24qMTAwLDEpKSAlPiUgDQogIGRwbHlyOjpzZWxlY3QoLXRvdGFsX21vdGl2YXRpb24pDQoNCmxpZ2h0X2FsbCA8LSAgbGlnaHQgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkodmFsaWRpdHlfbGlnaHRfY3ljbGUpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IHN1bShuKSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHN0dWR5X21vdGl2YXRpb24gPSAiT3ZlcmFsbCIsDQogICAgICAgICAgICAgICAgcGVyY2VudCA9IHJvdW5kKG4vc3VtKG4pKjEwMCwxKSkgDQogIA0KDQpsaWdodF9hbGwgPC0gcmJpbmQobGlnaHRfYWxsLCBsaWdodCkgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKHZhbGlkaXR5X2xpZ2h0X2N5Y2xlID09ICJZZXMiKQ0KbGlnaHRfYWxsDQpgYGANCg0KDQojIyAxOC45IEV4cG9zdXJlIGR1cmF0aW9uIChDUkVEIFExNCkNCg0KIyMgMTguOS4xIE1pbmltdW0gZHVyYXRpb24NCg0KDQpgYGB7cn0NCm1pbl9kdXJhdGlvbiA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lDQogIGRwbHlyOjpncm91cF9ieShjb21wb3VuZF9taW5fZHVyYXRpb25fZXhwb3N1cmUsIHN0dWR5X21vdGl2YXRpb24pICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IG4oKSkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHRvdGFsX21vdGl2YXRpb24gPSBzdW0obikpICU+JSANCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjptdXRhdGUocGVyY2VudCA9IHJvdW5kKG4vdG90YWxfbW90aXZhdGlvbioxMDAsMSkpICU+JSANCiAgZHBseXI6OnNlbGVjdCgtdG90YWxfbW90aXZhdGlvbikNCg0KbWluX2R1cmF0aW9uX2FsbCA8LSAgbWluX2R1cmF0aW9uICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KGNvbXBvdW5kX21pbl9kdXJhdGlvbl9leHBvc3VyZSkgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gc3VtKG4pKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoc3R1ZHlfbW90aXZhdGlvbiA9ICJPdmVyYWxsIiwNCiAgICAgICAgICAgICAgICBwZXJjZW50ID0gcm91bmQobi9zdW0obikqMTAwLDEpKQ0KICANCg0KbWluX2R1cmF0aW9uX2FsbCA8LSByYmluZChtaW5fZHVyYXRpb25fYWxsLCBtaW5fZHVyYXRpb24pICU+JSANCiAgZHBseXI6OmZpbHRlcihjb21wb3VuZF9taW5fZHVyYXRpb25fZXhwb3N1cmUgPT0gIk5vdCBzdGF0ZWQiKSAlPiUgDQogIGRwbHlyOjptdXRhdGUocGVyY2VudF9yZXBvcnRlZCA9IDEwMC1wZXJjZW50KQ0KbWluX2R1cmF0aW9uX2FsbA0KYGBgDQoNCiMjIDE4LjkuMiBNYXhpbXVtIGR1cmF0aW9uDQoNCmBgYHtyfQ0KbWF4X2R1cmF0aW9uIDwtIEVJUEFBQl9kYXRhYmFzZSAlPiUNCiAgZHBseXI6Omdyb3VwX2J5KGNvbXBvdW5kX21heF9kdXJhdGlvbl9leHBvc3VyZSwgc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gbigpKSAlPiUNCiAgZHBseXI6Omdyb3VwX2J5KHN0dWR5X21vdGl2YXRpb24pICU+JSANCiAgZHBseXI6Om11dGF0ZSh0b3RhbF9tb3RpdmF0aW9uID0gc3VtKG4pKSAlPiUgDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHBlcmNlbnQgPSByb3VuZChuL3RvdGFsX21vdGl2YXRpb24qMTAwLDEpKSAlPiUgDQogIGRwbHlyOjpzZWxlY3QoLXRvdGFsX21vdGl2YXRpb24pDQoNCm1heF9kdXJhdGlvbl9hbGwgPC0gIG1heF9kdXJhdGlvbiAlPiUgDQogIGRwbHlyOjpncm91cF9ieShjb21wb3VuZF9tYXhfZHVyYXRpb25fZXhwb3N1cmUpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IHN1bShuKSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHN0dWR5X21vdGl2YXRpb24gPSAiT3ZlcmFsbCIsDQogICAgICAgICAgICAgICAgcGVyY2VudCA9IHJvdW5kKG4vc3VtKG4pKjEwMCwxKSkNCiAgDQoNCm1heF9kdXJhdGlvbl9hbGwgPC0gcmJpbmQobWF4X2R1cmF0aW9uX2FsbCwgbWF4X2R1cmF0aW9uKSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIoY29tcG91bmRfbWF4X2R1cmF0aW9uX2V4cG9zdXJlID09ICJOb3Qgc3RhdGVkIikgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHBlcmNlbnRfcmVwb3J0ZWQgPSAxMDAtcGVyY2VudCkNCm1heF9kdXJhdGlvbl9hbGwNCmBgYA0KDQojIyAxOC4xMCBFeHBvc3VyZSB2ZXJpZmljYXRpb24gKENSRUQgUTE1KQ0KDQojIyAxOC4xMC4xIFdhdGVyIHZlcmlmaWNhdGlvbg0KDQpgYGB7cn0NCndhdGVyX3ZlcmlmaWNhdGlvbiA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lDQogIGRwbHlyOjpmaWx0ZXIoIWlzLm5hKHZhbGlkaXR5X2NvbXBvdW5kX3dhdGVyX3ZlcmlmaWNhdGlvbikpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHZhbGlkaXR5X2NvbXBvdW5kX3dhdGVyX3ZlcmlmaWNhdGlvbiwgc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gbigpKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIGRwbHlyOjptdXRhdGUodG90YWxfbW90aXZhdGlvbiA9IHN1bShuKSkgJT4lIA0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6Om11dGF0ZShwZXJjZW50ID0gcm91bmQobi90b3RhbF9tb3RpdmF0aW9uKjEwMCwxKSkgJT4lIA0KICBkcGx5cjo6c2VsZWN0KC10b3RhbF9tb3RpdmF0aW9uKQ0KDQp3YXRlcl92ZXJpZmljYXRpb25fYWxsIDwtICB3YXRlcl92ZXJpZmljYXRpb24gJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkodmFsaWRpdHlfY29tcG91bmRfd2F0ZXJfdmVyaWZpY2F0aW9uKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBzdW0obikpICU+JSANCiAgZHBseXI6Om11dGF0ZShzdHVkeV9tb3RpdmF0aW9uID0gIk92ZXJhbGwiLA0KICAgICAgICAgICAgICAgIHBlcmNlbnQgPSByb3VuZChuL3N1bShuKSoxMDAsMSkpIA0KICANCg0Kd2F0ZXJfdmVyaWZpY2F0aW9uX2FsbCA8LSByYmluZCh3YXRlcl92ZXJpZmljYXRpb25fYWxsLCB3YXRlcl92ZXJpZmljYXRpb24pICU+JSANCiAgZHBseXI6OmZpbHRlcih2YWxpZGl0eV9jb21wb3VuZF93YXRlcl92ZXJpZmljYXRpb24gPT0gIk1lYXN1cmVkIikNCndhdGVyX3ZlcmlmaWNhdGlvbl9hbGwNCmBgYA0KDQojIyAxOC4xMC4xIFRpc3N1ZSB2ZXJpZmljYXRpb24NCg0KYGBge3J9DQp0aXNzdWVfdmVyaWZpY2F0aW9uIDwtIEVJUEFBQl9kYXRhYmFzZSAlPiUNCiAgI2RwbHlyOjpmaWx0ZXIoIWlzLm5hKHZhbGlkaXR5X2NvbXBvdW5kX2FuaW1hbF92ZXJpZmljYXRpb24pKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieSh2YWxpZGl0eV9jb21wb3VuZF9hbmltYWxfdmVyaWZpY2F0aW9uLCBzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBuKCkpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHN0dWR5X21vdGl2YXRpb24pICU+JSANCiAgZHBseXI6Om11dGF0ZSh0b3RhbF9tb3RpdmF0aW9uID0gc3VtKG4pKSAlPiUgDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHBlcmNlbnQgPSByb3VuZChuL3RvdGFsX21vdGl2YXRpb24qMTAwLDEpKSAlPiUgDQogIGRwbHlyOjpzZWxlY3QoLXRvdGFsX21vdGl2YXRpb24pDQoNCnRpc3N1ZV92ZXJpZmljYXRpb25fYWxsIDwtICB0aXNzdWVfdmVyaWZpY2F0aW9uICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHZhbGlkaXR5X2NvbXBvdW5kX2FuaW1hbF92ZXJpZmljYXRpb24pICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IHN1bShuKSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHN0dWR5X21vdGl2YXRpb24gPSAiT3ZlcmFsbCIsDQogICAgICAgICAgICAgICAgcGVyY2VudCA9IHJvdW5kKG4vc3VtKG4pKjEwMCwxKSkgDQogIA0KDQp0aXNzdWVfdmVyaWZpY2F0aW9uX2FsbCA8LSByYmluZCh0aXNzdWVfdmVyaWZpY2F0aW9uX2FsbCwgdGlzc3VlX3ZlcmlmaWNhdGlvbikgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKHZhbGlkaXR5X2NvbXBvdW5kX2FuaW1hbF92ZXJpZmljYXRpb24gPT0gIlllcyIpDQp0aXNzdWVfdmVyaWZpY2F0aW9uX2FsbA0KYGBgDQoNCg0KIyMgMTguMTEgUmFuZG9taXphdGlvbiAoTm90IENSRUQpDQoNCmBgYHtyfQ0KcmFuZG9taXphdGlvbiA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lDQogIGRwbHlyOjpncm91cF9ieShhcnRpY2xlX2lkKSAlPiUgDQogIGRwbHlyOjpzYW1wbGVfbigxKSAlPiUgDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkodmFsaWRpdHlfcmFuZG9taXphdGlvbiwgc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gbigpKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIGRwbHlyOjptdXRhdGUodG90YWxfbW90aXZhdGlvbiA9IHN1bShuKSkgJT4lIA0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6Om11dGF0ZShwZXJjZW50ID0gcm91bmQobi90b3RhbF9tb3RpdmF0aW9uKjEwMCwxKSkgJT4lIA0KICBkcGx5cjo6c2VsZWN0KC10b3RhbF9tb3RpdmF0aW9uKQ0KDQpyYW5kb21pemF0aW9uX2FsbCA8LSAgcmFuZG9taXphdGlvbiAlPiUgDQogIGRwbHlyOjpncm91cF9ieSh2YWxpZGl0eV9yYW5kb21pemF0aW9uKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBzdW0obikpICU+JSANCiAgZHBseXI6Om11dGF0ZShzdHVkeV9tb3RpdmF0aW9uID0gIk92ZXJhbGwiLA0KICAgICAgICAgICAgICAgIHBlcmNlbnQgPSByb3VuZChuL3N1bShuKSoxMDAsMSkpIA0KICANCg0KcmFuZG9taXphdGlvbl9hbGwgPC0gcmJpbmQocmFuZG9taXphdGlvbl9hbGwsIHJhbmRvbWl6YXRpb24pICU+JSANCiAgZHBseXI6OmZpbHRlcih2YWxpZGl0eV9yYW5kb21pemF0aW9uID09ICJZZXMiKSAlPiUgDQogIGRwbHlyOjptdXRhdGUocGVyY2VudF9kaXNjbG9zZWQgPSAxMDAtcGVyY2VudCkNCnJhbmRvbWl6YXRpb25fYWxsDQpgYGANCg0KIyMgMTguMTIgQmxpbmRpbmcgKE5vdCBDUkVEKQ0KDQpgYGB7cn0NCmJsaW5kaW5nIDwtIEVJUEFBQl9kYXRhYmFzZSAlPiUNCiAgZHBseXI6Omdyb3VwX2J5KGFydGljbGVfaWQpICU+JSANCiAgZHBseXI6OnNhbXBsZV9uKDEpICU+JSANCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieSh2YWxpZGl0eV9iZWhhdl9ibGluZGluZywgc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gbigpKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIGRwbHlyOjptdXRhdGUodG90YWxfbW90aXZhdGlvbiA9IHN1bShuKSkgJT4lIA0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6Om11dGF0ZShwZXJjZW50ID0gcm91bmQobi90b3RhbF9tb3RpdmF0aW9uKjEwMCwxKSkgJT4lIA0KICBkcGx5cjo6c2VsZWN0KC10b3RhbF9tb3RpdmF0aW9uKQ0KDQpibGluZGluZ19hbGwgPC0gIGJsaW5kaW5nICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHZhbGlkaXR5X2JlaGF2X2JsaW5kaW5nKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBzdW0obikpICU+JSANCiAgZHBseXI6Om11dGF0ZShzdHVkeV9tb3RpdmF0aW9uID0gIk92ZXJhbGwiLA0KICAgICAgICAgICAgICAgIHBlcmNlbnQgPSByb3VuZChuL3N1bShuKSoxMDAsMSkpIA0KICANCg0KYmxpbmRpbmdfYWxsIDwtIHJiaW5kKGJsaW5kaW5nX2FsbCwgYmxpbmRpbmcpICU+JSANCiAgZHBseXI6OmZpbHRlcih2YWxpZGl0eV9iZWhhdl9ibGluZGluZyA9PSAiWWVzIikNCmJsaW5kaW5nX2FsbA0KYGBgDQoNCiMjIDE4LjEzIFNjb3JpbmcgbWV0aG9kIChOb3QgQ1JFRCkNCg0KYGBge3J9DQpiZWhhdl9zY29yaW5nIDwtIEVJUEFBQl9kYXRhYmFzZSAlPiUNCiAgZHBseXI6Omdyb3VwX2J5KGFydGljbGVfaWQpICU+JSANCiAgZHBseXI6OnNhbXBsZV9uKDEpICU+JSANCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIHRpZHlyOjpzZXBhcmF0ZV9yb3dzKHZhbGlkaXR5X2JlaGF2X3Njb3JpbmdfbWV0aG9kLCBzZXAgPSAiOyIpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHZhbGlkaXR5X2JlaGF2X3Njb3JpbmdfbWV0aG9kLCBzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBuKCkpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHN0dWR5X21vdGl2YXRpb24pICU+JSANCiAgZHBseXI6Om11dGF0ZSh0b3RhbF9tb3RpdmF0aW9uID0gc3VtKG4pKSAlPiUgDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHBlcmNlbnQgPSByb3VuZChuL3RvdGFsX21vdGl2YXRpb24qMTAwLDEpKSAlPiUgDQogIGRwbHlyOjpzZWxlY3QoLXRvdGFsX21vdGl2YXRpb24pDQoNCmJlaGF2X3Njb3JpbmdfYWxsIDwtICBiZWhhdl9zY29yaW5nICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHZhbGlkaXR5X2JlaGF2X3Njb3JpbmdfbWV0aG9kKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBzdW0obikpICU+JSANCiAgZHBseXI6Om11dGF0ZShzdHVkeV9tb3RpdmF0aW9uID0gIk92ZXJhbGwiLA0KICAgICAgICAgICAgICAgIHBlcmNlbnQgPSByb3VuZChuL3N1bShuKSoxMDAsMSkpIA0KICANCg0KYmVoYXZfc2NvcmluZ19hbGwgPC0gcmJpbmQoYmVoYXZfc2NvcmluZ19hbGwsIGJlaGF2X3Njb3JpbmcpICU+JSANCiAgZHBseXI6OmZpbHRlcih2YWxpZGl0eV9iZWhhdl9zY29yaW5nX21ldGhvZCA9PSAibm90IHNwZWNpZmllZCIpICU+JSANCiAgZHBseXI6Om11dGF0ZShwZXJjZW50X3NwZWNpZmllZCA9IDEwMC1wZXJjZW50KQ0KYmVoYXZfc2NvcmluZ19hbGwNCmBgYA0KDQojIyAxOC4xNCBDb25mbGljdCBzdGF0ZW1lbnQgKE5vdCBDUkVEKQ0KDQpgYGB7cn0NCmNvbmZsaWN0IDwtIEVJUEFBQl9kYXRhYmFzZSAlPiUNCiAgZHBseXI6Omdyb3VwX2J5KGFydGljbGVfaWQpICU+JSANCiAgZHBseXI6OnNhbXBsZV9uKDEpICU+JSANCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieSh2YWxpZGl0eV9jb25mbGljdF9zdGF0ZW1lbnQsIHN0dWR5X21vdGl2YXRpb24pICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IG4oKSkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHRvdGFsX21vdGl2YXRpb24gPSBzdW0obikpICU+JSANCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjptdXRhdGUocGVyY2VudCA9IHJvdW5kKG4vdG90YWxfbW90aXZhdGlvbioxMDAsMSkpICU+JSANCiAgZHBseXI6OnNlbGVjdCgtdG90YWxfbW90aXZhdGlvbikNCg0KY29uZmxpY3RfYWxsIDwtICBjb25mbGljdCAlPiUgDQogIGRwbHlyOjpncm91cF9ieSh2YWxpZGl0eV9jb25mbGljdF9zdGF0ZW1lbnQpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IHN1bShuKSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHN0dWR5X21vdGl2YXRpb24gPSAiT3ZlcmFsbCIsDQogICAgICAgICAgICAgICAgcGVyY2VudCA9IHJvdW5kKG4vc3VtKG4pKjEwMCwxKSkgDQogIA0KDQpjb25mbGljdF9hbGwgPC0gcmJpbmQoY29uZmxpY3RfYWxsLCBjb25mbGljdCkgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKHZhbGlkaXR5X2NvbmZsaWN0X3N0YXRlbWVudCA9PSAiTm8gc3RhdGVtZW50IGlzIG1hZGUgaW4gdGhlIHBhcGVyIikgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHBlcmNlbnRfc3BlY2lmaWVkID0gMTAwLXBlcmNlbnQpDQpjb25mbGljdF9hbGwNCmBgYA0KDQoNCiMgMTkgUiBTZXNzaW9uIEluZm9ybXRpb24NCg0KYGBge3J9DQojIHBhbmRlciBmb3IgbWFraW5nIGl0IGxvb2sgbmljZXINCnNlc3Npb25JbmZvKCkgJT4lIHBhbmRlcigpDQpgYGANCg0K